ラムネグから一言:寝る前に読むとくだらなすぎて逆に寝れると好評なすごい適当なブログをこっちではじめてます.
laravelの説明書読んでてイマイチピンとこなかったのがこれ。
デフォルトでは、LaravelはHTTPリクエストのhostヘッダの内容に関係なく受信したすべてのリクエストにレスポンスします。さらに、Webリクエスト中にアプリケーションへの絶対URLを生成するときに、hostヘッダの値を使用します。引用:https://readouble.com/laravel/10.x/ja/passwords.html
いったい何を言ってるんだ?と思ってたらどうやら「ホストヘッダインジェクション攻撃」と呼ばれるものに関する脆弱性を書いているみたい。
ここではホストヘッダインジェクション攻撃ってなに?っていうのを書きます。
- HTTP通信でやり取りされる「HOSTヘッダ」を改ざんする攻撃
- 話飛んで「パスワードを忘れた」の話
- このパスワードリセット機能でlaravelだと問題があるっぽい
- なぜHOSTヘッダからリンクを作るのか疑問すぎる
- laravelの他の認証システムは大丈夫なの?
- 「ホストヘッダインジェクション攻撃」対策
- まとめ
HTTP通信でやり取りされる「HOSTヘッダ」を改ざんする攻撃
「ホストヘッダインジェクション攻撃」っていうのを簡単に書くと「HTTP通信でやり取りされるHOSTヘッダを改ざんする攻撃」という事になります。
HOSTヘッダっていうのは、WEBを見る側、つまり閲覧者側が、サーバに対して「僕このサービスにアクセスしたいな」って閲覧したいサイトのURLを書く場所なんです。
つまりこのラムネグを見てくれてる人でいうならHOSTヘッダには勝手に「blog.dododori.com」と入っているわけです。で、これは閲覧してる側が任意に替えれるのですごく簡単に改ざんできる、と。
でも、通常HOSTヘッダに何が書かれてても関係ないんで改ざんされても痛くもかゆくもないんです。でも…、
話飛んで「パスワードを忘れた」の話
ここで話が飛びますが、アマゾンでもなんでもログイン機能のあるサイトだと何度かログインに失敗すると「パスワードを忘れた」っていうボタンが出てきますよね。
「パスワードを忘れた」を押すと登録時のメールアドレスの入力を求められて、んで入力するとそのメールアドレスにパスワードリセット用のメールがリンク付きで届く、的な。
よくあるやつなので皆さん1回くらいはお世話になったことがあると思います。
このパスワードリセット機能でlaravelだと問題があるっぽい
この一見すると全く関係のない「ホストヘッダインジェクション攻撃」と「パスワードリセット」が合わさると脆弱性が出てくる、というのが重要になります。
この記事の一番最初に書いたlaravelの説明で、「Webリクエスト中にアプリケーションへの絶対URLを生成するときに、hostヘッダの値を使用します。」というのがあります。
これの言わんとしてることは、「パスワードを忘れた」で「ユーザーに送るメールのパスワードリセット用のリンクを作るときにこのHOSTヘッダの値使うからね!」って事…みたい。
まだ相当わかりづらいんで昔話風に書くと…、
登場人物
- laravel.com:ログイン機能のある普通のサイト
- 悪井さん:悪い人
- warui.com:悪井さんが用意したダミーサイト
- 普通さん:laravel.comに登録している普通の人。なぜか悪井さんから恨みをかっている
の4名
お話
- 悪井さん「ふっふっふ、このlaravel.comっていうサイトはログイン機能があるぞ!しかもlaravelじゃねぇか。ならこのlaravel.comに登録してるであろう普通さんのパスワードを盗めるかもしれねぇ」
- 悪井さん「とりあえずlaravel.comのパスワードを忘れたボタンをクリックしてっと。んでメールアドレスには普通さんのメールアドレスを入力。おっと、HOSTヘッダはオレの作ったwarui.comに書き換えて、っと。はいポチっと。」
- laravel.com「あらあら、まあまあ、普通さんたらパスワードを忘れてしまったのね。ならHOSTヘッダに書かれてるURL(warui.com)を使ってパスワードリセット用のリンクを作って送ってあげなくちゃ♪」
- 普通さん「あれ?laravel.comからメールだ。なになに?パスワードリセット?うーん、確かに最近パスワード変えてなかったからなぁ…、入力しておくか。メールのリンクポチ」
- warui.com「パスワードを入力してください」
- 普通さん「んじゃ普段使ってるやつでいいや。はい、パスワード設定完了っと」
- 悪井さん「へへへっ…、これで普通さんが使ってるパスワードをGETできたわけだ!」
という。流れで漏洩するんですね。
少しは解りやすくなったでしょうか。
なぜHOSTヘッダからリンクを作るのか疑問すぎる
結局キモはなぜいくらでも改ざんできるHOSTヘッダの値でパスワード再設定用リンクを作っちゃうのか、っていう部分。
これをしてなければそもそもホストヘッダインジェクション攻撃なんて成り立たないんですよね。
HOSTヘッダの情報なんて使わなくても、そもそもそのサーバ上で動いているのがそのWEBサービス(今回で言うとlaravel.com)なんだから自分のアドレスをそのまま使えばいいのに、本当に謎仕様すぎて理解ができません。
laravelの他の認証システムは大丈夫なの?
laravelにはログイン機能を作るための方法が4つくらいあります。
- 自分でセコセコ全部書く
- laravel Fortify
- laravel Breeze
- laravel Jetstream
名前も全部ややこしいことこの上ないんですよねこれ。全部ログインのための仕組みでどれか1つ選んで使うんですが、こんなの全部「laravel login-kit」みたいなわかりやすい名前にしておいて欲しいです。
一応説明しておくと上から順番に機能が少なくなっていて「Fortify」は画面の見た目とかは自分で作らないといけません。「Breeze」は入れるだけでログイン機能が全部入ります。「Jetstream」はさらに機能が豊富でよくわかりませんがいろいろついてるやつです。
そしてこのホストヘッダインジェクション攻撃に関して、とりあえずBreezeしか今の所使ってませんが特に対策されているようには見えません。
うーん、それでいいのかな、laravel。実際は見えないところで対策されてるのかもしれませんが上の説明書で書いてある「TrustHostsミドルウェア」も有効になってなかったし、よくわかりません。
「ホストヘッダインジェクション攻撃」対策
laravelでは上記説明書によると「TrustHostsミドルウェア」を有効にすればHOSTヘッダの確認をしてくれるようになる(だからなんで自サーバのアドレスをそのまま使わないんだろう…)んですが、そのほかにもapacheでホストヘッダインジェクション攻撃対策をする事もできるみたい。
apacheのバーチャルホスト機能を使うみたいです。
まとめ
laravelのログイン機能、それからホストヘッダインジェクション攻撃について書きました。
まとめるとなんでHOSTヘッダなんていう改ざんし放題の値をパスワードリセット用のURL生成に使ってるのかマジイミフ!っていう感じです。
laravel以外にもDockerとかにもそういう仕様というか脆弱性みたいなのがある(あった?)みたいですが、逆にHOSTヘッダの情報からリンクを作成するどこにメリットがあるんでしょう…?本当によくわかりません。
今までlaravelではメール認証のログインシステムを一度も作ったことがない(ツイッター認証の「わたガチャ」「みんガチャ」「litty」の3つのみ)ので気にしてませんでしたが、けっこう面倒そうです。
【おしらせ、というか完全なる宣伝】
文体がもうぜんぜん適当すぎてあれだけどものすごい自由に書いてるブログ「檸檬だくだく」もよろしく.寝る前に読める恐ろしくくだらないやつです.
こんなにも一ミリも目を引かれないタイトルを取り扱ってます: ココア20g / ハイチュウとかってさ / なぜ米と小麦を食べようと思ったのかの謎 /