Brute Force 攻撃対策
以前紹介したレートリミットを使って Brute Force 攻撃対策をシミュレーションしてみます。
今回はユーザー名を切り替えて繰り返しログイン認証を試みるリクエストを例にします。
ログイン認証がフォーム入力の場合
POST メソッドで試します。 Body(application/x-www-form-urlencoded)の "username" にユーザー名(Email アドレス)が入ってくると想定します。
テストでは同じ IP から
username=a%40example.com
username=b%40example.com
username=c%40example.com
への接続を 2 回繰り返します。
~ $ for i in `seq 0 1`; do for u in a b c; do echo -n $u-$i; curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=$u%40example.com&password=1" -v 2>&1 | grep "< HTTP/2"; done; done
レートリミットは 10 秒間に 1 回を上限に設定にしておきます。
単一の IP アドレスを対象にする
ユーザー名ごとにレート制限
- 単一の IP アドレスから複数ユーザー名への接続試行をカウント
- ユーザー名ごとにレートリミットを適用
上記のリクエストマッチのフィルター、その他の設定は本実験用のものになります。実際の環境によってカスタマイズしてください。
実行結果を見ると、それぞれの username ごとに 2 回目の接続からレートリミットされ、Status code が 429 で帰ってきています。(Then take action...
設定の通り)
a-0< HTTP/2 200
b-0< HTTP/2 200
c-0< HTTP/2 200
a-1< HTTP/2 429
b-1< HTTP/2 429
c-1< HTTP/2 429
キモはこちらです。
クラス分けに "IP" と ”Form input value of" で username を指定することでカウントを分けています。
ユーザー名関係なく制限
- 単一の IP アドレスからの接続試行をカウント
- レートリミットを適用
ユーザー名を気にせず、同じ IP からのログイン試行をレートリミットする場合は、With the same characteristics ...
を "IP" のみにします。
ユーザー名に関わらず、同一 IP からの接続がまるっとレートリミットされます。
a-0< HTTP/2 200
b-0< HTTP/2 429
c-0< HTTP/2 429
a-1< HTTP/2 429
b-1< HTTP/2 429
c-1< HTTP/2 429
単一のユーザー名を対象にする
上記の例では、異なる IP は個別にレートリミットがされ、お互いに影響は受けません。
host1:~$ curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=a%40example.com&password=1" -v 2>&1| grep "< HTTP/2"
< HTTP/2 200
host2:~$ curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=a%40example.com&password=1" -v 2>&1 | grep "< HTTP/2"
< HTTP/2 200
これを
- 単一のユーザー名への接続試行をカウント
- レートリミットを適用
に変更します。
単一ユーザー名に対するアクセスを IP アドレスに関わらず制限するには、With the same characteristics ...
を Form input value of
"username" のみにします。
結果を見ると、username=a%40example.com への接続が IP を問わずレートリミットされます。
host1:~$ curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=a%40example.com&password=1" -v 2>&1| grep "< HTTP/2"
< HTTP/2 200
host2:~$ curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=a%40example.com&password=1" -v 2>&1 | grep "< HTTP/2"
< HTTP/2 429
ログイン認証が JSON での入力の場合
フォーム入力に加え、JSON での場合も同様に制御ができます。
~ $ for i in `seq 0 1`; do for u in a b c; do echo -n $u-$i; curl https://nrt.oyama.cf/post -s -H 'content-type: application/json' -d '{"username":"'$u'@example.com", "password":"1"}' -v 2>&1 | grep "< HTTP/2"; done; done
a-0< HTTP/2 200
b-0< HTTP/2 200
c-0< HTTP/2 200
a-1< HTTP/2 429
b-1< HTTP/2 429
c-1< HTTP/2 429
アクセス失敗のときだけカウントする
以前の記事 にあるようにサーバーのレスポンスを見て、アクセス失敗の試行だけカウントアップすることもできます。
たとえば、アクセス失敗時ににサーバーが 403 を返す(あるいは任意のヘッダーを返す)場合は下記のような設定で、アクセス失敗を繰り返す IP のみ制限することができます。
その他の機能との合せ技
Rate limiting rules 単体でもリクエストをルールにマッチさせる条件やマッチした場合のアクションなど、柔軟に定義、利用環境に合わせたカスタマイズが可能です。
ただ、その他の機能との合わせ技で、効果を高めることが期待できます。
たとえば Bot Management を組み合わせます。
Bot Score が 20 以下であれば、Block するというような WAF の Custom Rules を定義しておけば、レートリミットの前に、不要なものはそもそもブロックする、ということができます。
Bot score が 20 以下の端末からリクエストを投げると、403 が返ってきます(Custom rules による Block)。
$ curl https://nrt.oyama.cf/post -s -H 'content-type: application/x-www-form-urlencoded' -d "username=a%40example.com&password=1" -v 2>&1 | grep "< HTTP/2"
< HTTP/2 403
ルールの Action を Block から Log に変えた場合は下記になり、Rate Limiting Rules は Custom Rules のあとに来ています。
認証そのものを Access にオフロードするアーキテクチャも可能です。
API がエンドポイントの場合は、API Shieldとの組み合わせもできます。
以上です。
どのようなケースで使えそうか、ご検討の材料になれば幸いです。