IPアドレス総当りでサーバーを見つけて脆弱性スキャンを始める輩を、Hostヘッダーで撃退したい
WAFを導入してから特に気になったんだけど、リリース前のWebサービスが既に攻撃(脆弱性スキャン)を受けていることがある。同僚に尋ねたら「AWSが持っているIPアドレスの範囲を自動的に攻撃してるんじゃない?」とのこと。なるほど。
一方、 vercel.com でWebサイトをホストする際は、それらのWebサイトは同じIPアドレスで管理されることがある(76.76.21.21)。
つまり、IPアドレスだけではなくホスト名で処理を分岐させることが可能ということだ。
これを応用すればIPアドレスに対する自動的な攻撃は防げるのでは無いだろうか?
Chromeからホスト名にアクセスした場合とIPアドレスにアクセスした場合のリクエストをcURLとして抽出してみました。
authorityヘッダーが怪しく思えますが、先に申し上げるとこの有無で結果が変わりませんでした。authorityヘッダーは疑似ヘッダーフィールドといって、HTTP2の挙動を助ける仕様のようです。
##### to Hostname
curl 'https://justincase.jp/' \
-H 'authority: justincase.jp' \
-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
-H 'accept-language: ja,en-US;q=0.9,en;q=0.8' \
-H 'sec-fetch-dest: document' \
-H 'sec-fetch-mode: navigate' \
-H 'sec-fetch-site: none' \
-H 'sec-fetch-user: ?1' \
-H 'sec-gpc: 1' \
-H 'upgrade-insecure-requests: 1' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36' \
--compressed
##### to IP Address
curl 'http://76.76.21.21/' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
-H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \
-H 'Connection: keep-alive' \
-H 'Sec-GPC: 1' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36' \
--compressed \
--insecure
続いて、Firefoxからアクセスした場合をWiresharkで除いてみました。
HTTPレイヤーはTLSで暗号化されているので、こちらの記事にお世話になっています。
Wireshark で HTTP/2 over TLS の通信をダンプする方法
やっぱり、Hostヘッダーがありますね(というかChromeのインスペクターとcURL出力にHostヘッダーが無かったの、なんでなんだろう...?)
比較のために、Firefoxから 76.76.21.21 にもアクセスしてみました。
Hostが 76.76.21.21 になってますね。やっぱりここで判別してるのかしら。
調べてみるとHostヘッダーでアクセス先を識別するのは真っ当なやりかたのようだ。
Webサーバ/IPアドレス/ポート番号を追加したりすることなく、Webサイトを増設したいことがある。それにはWebサイトごとにホスト・ヘッダ値を設定するという方法がある。
cURLでHostヘッダーの有無で試してみた。確かにアクセス先が変わっているようだ。
### Hostヘッダーあり
% curl 'http://76.76.21.21/' \
-H 'Host: justincase.jp' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
-H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \
-H 'Connection: keep-alive' \
-H 'Sec-GPC: 1' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36' \
--compressed \
--insecure
<!doctype html>
<!-- https://vercel.app -->
<h1>Redirecting (308)</h1>
<a>https://justincase.jp/</a>
### Hostヘッダーなし
% curl 'http://76.76.21.21/' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
-H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \
-H 'Connection: keep-alive' \
-H 'Sec-GPC: 1' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36' \
--compressed \
--insecure
<!doctype html>
<!-- https://vercel.app -->
<h1>Redirecting (308)</h1>
<a>https://vercel.com/</a>
しかし、こんな単純なこと(Hostヘッダーで攻撃が防げるのでは?)に攻撃者が気づかないだろうか?
気になったので、Hostヘッダーに注目して攻撃を眺めてみた。すると2種類に大別されることが分かった。
1. Hostヘッダー = IPアドレス
フレームワークの脆弱性やGit初心者にありがちなミスを狙った気軽な攻撃。例を挙げると、
## .env の誤コミット狙い
GET /.env
Host: ***.***.***.***
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip
Connection: close
## とりあえずルート
GET /
Host: ***.***.***.***
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: */*
Accept-Encoding: gzip
2. Hostヘッダー = 暗号通貨取引所など、有名サービス
justincase.jp を狙ったものではなく、仮想通貨取引所など有名サービスの未公開エンドポイントを探していると思われる攻撃。例を挙げると、
GET /bapi/fiat/v1/public/fiatpayment/menu?currency=CNY
Accept: application/json, text/plain, */*
Host: www.binance.com
User-Agent: BNC/2.37.0 (build 10; iOS 14.8.0) Alamofire/4.9.0
Mclient-X-Tag: pch5D9lsORjgObhyjdSK
timeout: 3000
Connection: close
GET /open/api/v2/market/depth?symbol=BTC_USDT&depth=1
Accept: application/json, text/plain, */*
Host: www.mexc.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
Connection: close
Binanceともなると、未公開のエンドポイントを見つけるためだけにIPアドレスを全スキャンする輩が現れるんですね。セキュリティ担当者大変そう...(実際、物理的な誘拐とかも気をつける必要がありそう)
で、調べてみると流石に先人はいらっしゃいますね。
- ALBへのアクセスを特定のHostヘッダのみに限定する方法の一例 | DevelopersIO
- AWS WAFでHost Header +IP Addressでアクセス制限してコミュ症ウェッブアプリケーションを作ろう | iret.media
ELBで捌いてもいいんだけど、4XXのメトリクスが使い物にならなくなるのが玉に瑕かなぁ...
WAFルールを作る方法で考えてみましょう。おしまい。