僕が借りているサーバが、世界各国から「1日900回」不正アクセスされている話〜/var/log/secureからみえる攻撃者の影〜
私用で使っているサーバの/var/log/secureをみてみた
見に覚えのないアクセスが大量にある。。。
しかもuserはrootだったりadminだったり。。。
これ、不正アクセスってやつか?
1日どれくらい不正アクセスを試みられているのか
2/4の不正アクセス回数を、すごい雑な方法だけどしらべてみた。
$ cat /var/log/secure | awk '/Feb 4/ && /Failed/' | wc -l 943
わお。943回。どこから不正アクセスされているんだろ。
いったんipだけ抽出して、
どこの国から狙われているか調査してみた。
使用unixコマンド
ここらへんを知っておくとログ調査に便利。
調査手順
ipアドレスのみ抽出
$ grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' /var/log/secure > ips.txt
-Eオプションで正規表現が使えます
40.69.203.57 40.69.203.57 40.69.203.57 172.31.32.142 94.183.180.86 94.183.180.86 94.183.180.86 ...
※ 念のためipアドレスは編集しております
ipの重複をなくす
sort ips.txt | uniq > unique_ips.txt
sortしてuniqして、ipをuniqueにします。
101.78.196.27 103.16.142.208 103.20.251.158 103.213.115.45 103.216.205.51 103.22.171.1 ...
ipがユニークになった。
ipジオロケーションサービスに投げる
$ curl http://api.hostip.info/get_html.php\?ip=40.69.203.57
これを投げると、
Country: UNITED STATES (US) City: (Unknown city) IP: 40.69.203.57
いい感じにデータが返ってきます。
#!/bin/bash while read ip do curl http://api.hostip.info/get_html.php\?ip=$ip\&position=true done < unique_ips.txt
run.shという名前で保存して、
$ sh run.sh > countries.txt
こんな感じで走らせ、結果をテキストファイルに保存します。
awkコマンドで国だけ抽出
$ cat countries.txt | awk '/Country/' | sort | uniq
とすると、先ほどの結果の「Country」だけ抽出できます。
結果
Country: (Private Address) (XX) Country: (Unknown Country?) (XX) Country: AUSTRALIA (AU) Country: AUSTRIA (AT) Country: BRAZIL (BR) Country: BULGARIA (BG) Country: CANADA (CA) Country: CHILE (CL) Country: CHINA (CN) Country: COLOMBIA (CO) Country: CROATIA (HR) Country: DENMARK (DK) Country: EUROPEAN UNION (EU) Country: FRANCE (FR) Country: GERMANY (DE) Country: HONG KONG (HK) Country: HUNGARY (HU) Country: INDIA (IN) Country: INDONESIA (ID) Country: IRELAND (IE) Country: ISRAEL (IL) Country: ITALY (IT) Country: JAPAN (JP) Country: KOREA, REPUBLIC OF (KR) Country: MALAYSIA (MY) Country: MEXICO (MX) Country: NETHERLANDS (NL) Country: NORWAY (NO) Country: PAKISTAN (PK) Country: PERU (PE) Country: PHILIPPINES (PH) Country: POLAND (PL) Country: RUSSIAN FEDERATION (RU) Country: SENEGAL (SN) Country: SLOVENIA (SI) Country: SPAIN (ES) Country: SWITZERLAND (CH) Country: TAIWAN (TW) Country: THAILAND (TH) Country: UKRAINE (UA) Country: UNITED KINGDOM (GB) Country: UNITED STATES (US) Country: VIET NAM (VN)
おおー。
世界各国から狙われている笑
攻撃元を特定するのは難しい
ただ、これだけだと発信元を特定するのは難しい。
攻撃者はいくつもの踏み台サーバを使って攻撃することにより、
自分の発信元を特定しにくくしているから。
なので、世界各国からアクセスされているからと言って、
本当に世界各国の人が狙っているかどうかはわからない。
攻撃を回避するには
色んな方法があるが、
今回はポート番号を変えてみた(次回)
puttyからsshでログインしようとした時に、Disconnected: No supported authentication methods availableと言われてしまった
puttyを使ってsshでパスワード認証を使ってログインしようとした
こんなエラーが表示されました。
Disconnected: No supported authentication methods available
とりあえずサーバに入り、/etc/ssh/sshd_configをみてみる
いろいろな原因が考えられるが、とりあえずサーバの設定ファイルをみてみた。
PasswordAuthentication no
パスワード認証が使えないように設定されている。
だいぶ前にいじったから忘れてた。
セキュアじゃなくなるけど
一旦
PasswordAuthentication yes
とした。そうしたらログインできるようになった。
その後、すぐにnoに戻した。
Angularを使って、カートで商品を選択する画面を作ってみた〜親子コンポーネント・サービス間連携をしてみる〜
Angularの復習をしようと思った
今回の開発で、Angularを使った。
基本フロント側は一人で開発をしていたが、
1画面で扱っているコンポーネントの数が600個をこえたり、
画面間で引き継ぐ項目がどんどん増えてきたりで、
だんだん大変なことになってきた。
なぜ大変な事になってきたか
サービス増えすぎ問題
それぞれのコンポーネントで値(以下、モデル)を共有させようとした時に、
サービスをDIして共有させていた。
モデルごとにサービスを作ってしまっていたので、
モデルが増えるたびにサービスが増え、大変なことになってしまった。
サービスの役割2つあるよ問題
ページ間をまたがないデータはコンポーネントに持たせればよいのに、
なぜかサービスにデータを持たせてしまっていた。
よって、
サービスが「データの保持」「データ処理」の2つの役割を持ってしまっていた。
サービスの役割が曖昧になり、追加でいじる時にどこをいじればよいのかわかりにくくなってしまっていた。
作ったのがこれ
説明
構成
最上位にAppComponentをおく。
このコンポーネントが、この画面で扱うすべてのプロパティを保持している。
子供はAppComponentのプロパティを共有している。
子供で起こったイベントは、AppServiceを通じてAppComponentに伝えられる。
商品をクリックした時、どのように画面が変更されるか
クリックしたことをAppServiceに伝える
AppServiceは、AppComponentが持っているプロパティを操作する
子コンポーネントに、AppComponentのプロパティ変更が伝わる
子コンポーネントは親のプロパティを共有しているので、
そのまま親のプロパティの変更が伝わります。
画面に結果があらわれる
まとめ
今回、AppComponentに画面上で扱うすべてのプロパティをもたせたので、
シンプルになった。
また、AppServiceを用いたことにより、
子供から親へのイベントバブリングと言った複雑なことをしなくても良くなった。
今後はこういう設計にしていきたいなぁ。
module.exportsとは何か、どうもわからなかったので実験してみた〜Node.jsにて外部moduleをrequireする〜
いきさつ
今まで何も考えずに
npm install
して、
var module = require('module-name');
して使ってきたが、
Node.jsについて知らなさすぎて、
node_moduleディレクトリ配下に格納されているmoduleをみても、
ぜんぜん読めないことに気づいた。
exports.moduleが分かればだいぶ読めるようになるかな、と思い、
まずはexports.moduleについて理解することにした。
ディレクトリ構造
├── main.js └── node_modules └── weather-module.js
やってること
main.jsからweather-module.jsを読み込む。
// main.js var weather = require('weather-module'); weather.today(); weather.yesterday();
// weather-module.js /** weatherオブジェクトの生成 */ var weather = {}; weather.today = function() { console.log('晴れだよ'); } weather.yesterday = function() { console.log('雨だったよ'); } module.exports = weather;
わからないこと
module.exports = weather;
の部分で何をやっているのかわからない。
結論
// main.js require('weather-module');
requireが、
weather-module.jsでmodule.exportsに渡されているオブジェクトを
返してくれるので、それを使用することができる。
実験手順
何を読み込んでいるのか調べる
これを外部ファイル(main.js)から読み込んで使いたい。
// main.js var weatherModule = require('weather-module'); console.log(weatherModule);
main.jsを実行
$ node main.js { today: [Function], yesterday: [Function] }
weatherオブジェクトそのものが渡っているようである。
weatherオブジェクトはmodule.exportsに渡されているのものなので、
require('weather-module');
はmodule.exportsに渡されているオブジェクトを返す、と考えられる。
module.exportsに複数のオブジェクトを渡してみる
/** weatherオブジェクトの生成 */ var weather = {}; weather.today = function() { console.log('晴れだよ'); } /** 関数の追加2 */ weather.yesterday = function() { console.log('雨だったよ'); } /** temperatureオブジェクトの生成 */ var temperature = {}; temperature.today = function() { console.log('25'); } temperature.yesterday = function() { console.log('15'); } module.exports = { weather: weather, temperature: temperature // もう一個渡す };
main.jsを実行
$ node main.js { weather: { today: [Function], yesterday: [Function] }, temperature: { today: [Function], yesterday: [Function] } }
やはり、
require('weather-module');
module.exportsに渡されているオブジェクトを返すようだ。
まとめ
require('hoge-module');
hoge-module.jsにて、
module.exportsに渡されているオブジェクトを返す。
逆に言えば、
module.exportsに渡していないオブジェクトは使えない。
外部から使用したいオブジェクトは、必ずmodule.exportsに渡すこと。
参考
本番環境にテストデータを入れてしまったときは、deleteではなくtruncateでテーブルからレコードを一掃しよう〜deleteとtruncateの違い〜
いきさつ
社内で使用するシステムの開発が一旦落ち着いたので、
本番環境構築することになった。
といってもすでにテスト環境を構築しているので、
慣れたものである。
種々のインスタンスを立ち上げ、ansible用のユーザを作成し、
playbookの諸々の設定位置を少し書き換ええ、流すだけで良い。
(playbook、つくるのは大変だった)
で、いつものように本番環境にデプロイし終わり
きちんと登録できるか一通りの操作をした。
そこで先輩が一言
「本番環境上に作ってしまったデータは残してはいけないから、
きちんとtruncateしといてね」
僕はハッとした
当たり前だが、その一言に僕はハッとさせられた。
基本的に本番環境はまっさらな状態で、お客さんに使ってもらう。
使ってもらう時、
私たち開発者がテスト用に打ったゴミデータが入っていると、
アカウント管理をしているとはいえ、
万が一そのゴミデータのせいでバグが起こりうる場合もある。
(そもそも本番環境なので、
テストデータが紛れ込んでいると言うのはおかしい、というのもある)
なので
テストデータは消しておく必要がある。
そのときに注意しておくのがdeleteとtruncateの違いだ。
deleteとtruncateの違い
idがauto_incrementになっていた場合、
deleteは連番情報を保持したまま。
truncateは1から裁判し直す。
という違いがある。
まっさらな状態にする、という意味ではtruncateが適している。
まとめ
本番環境の扱いには気をつけよう。
シェルで文字列を比較したときに、[: =: unary operator expected :というエラーがでる
いきさつ
空行を検出するスクリプトを書いていた
古池や 蛙飛び込む 水の音
をシェルに読み込ませ、空行があったときに
「空行があるよ」というスクリプトを書いた。
※ 実際の処理を簡略化してます
#!/bin/bash while read line do if [ $line = '' ]; then echo '空行があるよ' fi done < line.txt
しかしうごかないんだなこれが
test.sh: line 4: [: =: unary operator expected
というエラーがでる。
どこでエラーが置きているかわからないので、
#!/bin/bash while read line do echo $line # ここで出力する if [ $line = '' ]; then echo '空行があるよ' fi done < line.txt
echo で毎行出力してみる。
古池や test.sh: line 5: [: =: unary operator expected 蛙飛び込む 水の音
どうやら空行を読み込んだ時に起きているエラーのようだ。
調べてみた
変数に格納されている文字列比較において、 文字列の比較は文字列と行う必要があるところを、 文字列と何かわからない型の変数を比較してしまっているので、 このようなエラーが発生するらしい。
空行は「文字列かわからない型」なのか…?
ちょっとそこは釈然としない。
対処
#!/bin/bash while read line do if [ "$line" = '' ]; then echo '空行があるよ' fi done < line.txt
$lineを""でかこむ。文字列にキャストしている感じなのかな。
結果
空行があるよ
動いた。
シェルは独特。でもサッとかけるから便利。
環境を選ばないしねぇ。
最強のポータビリティ言語である。