nginx + unicorn + sinatraで構築したWebサイト(nginx)で不正アクセスをアプリケーション層ではじく処理を書きたくなって、少しはまったので書いておきたいと思います。
■目次
$env["REMOTE_ADDR"]
Webアプリで不正アクセスを防ぐ場合、接続元のIPアドレスを見て、怪しいやつ(例.ログインフォームで何回もログインに失敗しているやつ)を出禁にしてしまうという手法が手っ取りばやいだろう。ということで、サイトへのログイン処理にそのような処理を入れてみました。
※銀行のオンラインバンキングなどでよくあるパスワード間違えるとログインできなくなるというやつですね。
sinatraでは接続元のIPアドレスは$env["REMOTE_ADDR"]という変数に格納されていますのでログイン失敗時にこのIPアドレスをチェックすることで比較的簡単にアクセス制限の処理はかけます。
$env["REMOTE_ADDR"]が 127.0.0.1 になる
実装していざ手元のPCで動作確認してみると、アクセス制限処理はちゃんと動いたのでよかったよかったと思って、続けて手持ちのスマホでも試してみましたが、なんとスマホからもログインできなくなっていました。
おかしいと思って接続元IPアドレスを見てみるとどちらの端末からもIPアドレスは 127.0.0.1になっていました。
それで気が付いたのですが アプリケーションを nginx と連携させる場合$env["REMOTE_ADDR"]には 127.0.0.1が入るようです。
nginxがプロキシになっているのでまぁ正しいと言えば正しいような気もしますが、知りたかったのは実際に外部から接続してきているIPアドレスなので、何か受け取る方法はないか調べてみました。
proxy_set_headerを設定する
調べてみると直ぐに見つかりました。
↓こちらの記事を参考にさせて頂きました。ありがとうございます。
stackoverflow.com
プロキシ経由時のリモートアドレスについて! - mk-mode BLOG
要するにnginx.confに
proxy_set_header X-Real-IP $remote_addr;
を追加すればよいようです。
例).
# ------------設定箇所抜粋 -------------
location / {
proxy_pass http://myapp;
proxy_set_header X-Real-IP $remote_addr; # ← ここを追加
}
この設定によりsinatra側では、@env["HTTP_X_REAL_IP"] に実際の接続元のIPアドレスが格納されるようになります。
※この辺は多分sinatraだけでなくRailsでも一緒だと思います。
感想
そもそもアクセス制限といった攻撃対策はルータの設定やiptablesの設定からきちんとしておくべきですね。
アクセス制限をかけようと思ったきっかけはnginxのアクセスログを見て、ちょくちょく攻撃を受けていることに気付いたからでした。
ログを見ていると中国やアメリカ、メキシコなどから攻撃と思われるアクセスがあり、攻撃方法はPHPのアプリケーションを想定しているらしく、
220.165.9.85 - - [10/Jul/2016:14:29:36 +0900] "GET //scripts/setup.php HTTP/1.1" 301 184 "-" "-"
220.165.9.85 - - [10/Jul/2016:14:29:58 +0900] "GET //phpmyadmin/scripts/setup.php HTTP/1.1" 301 184 "-" "-"
220.165.9.85 - - [10/Jul/2016:14:30:56 +0900] "GET //phpMyAdmin-2.5.5/index.php HTTP/1.1" 301 184 "-" "-"
のようなアクセスをされています。
こういう攻撃のされ方を見ていると、PHPを使う場合は特に気を付けておいた良さそうだなと思います。
PHPだと、企業のサイトなどでもWordPressがよく使われていたりしますが、実際WordPressの管理画面とかもザルになっていることが多いので、サイトを管理するときはセキュリティ意識高い系でないと危険だなと実感しました。