
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、この間LaravelでWebAuthnを使った2段階認証を実装するという記事を公開しましたが、特にウェブ開発にとってセキュリティは重要な位置づけであり続けると思います。(実際に、最近はある大手コンビニチェーンの決済システムの脆弱性が大々的に報じられ、閉鎖を決定してしまいました)
では、Laravel
はといえば最低限必要と思われるセキュリティ対策はすでに実装済みで、今回紹介する
CSRF(クロスサイト・リクエスト・フォージェリ)攻撃
についても対応してくれています。
ただ、このCSRF
攻撃。
名前は結構有名になったとは思いますが、「一体これってどんな攻撃なの?」って聞かれたらそれほど内容まで知らなかったりしないでしょうか。
もちろんすでにLaravelでは対策をとられているので、問題がないように思いますが、それでも前回お届けした記事LaravelでLINEにチャットボットをつくる(QRコード作成)のように、どうしてもCSRF
攻撃を解除しないといけない場合が出てくるのも事実です。
そこで!
今回は、知ってるようで知らないCSRF
攻撃について「できるだけ簡単に」説明をしてみたいと思います。
※ もしすでに知ってる方はおそらく真新しい内容は入っていないと思います。こちらからセキュリティに関する他の記事をお楽しみください゚
ぜひ皆さんのお役に立てると嬉しいです。
登場人物
善良さん:
今回CSRF
攻撃される普通のインターネット・ユーザー。
性格は、めんどくさがり。
「今日も大好きなネットショッピング!」
悪徳くん:
善良さんにCSRF
攻撃を仕掛ける愉快犯。
いたずら好き。
「うっしっし!!」
Amason:
架空の有名ネットショッピング・サイト。
CSRF攻撃が実行されるストーリー
では、まずはCSRF
攻撃が行われる可能性があるストーリーを見ていきましょう。善良さんの行動のどこに問題があったか、もしくはどこで攻撃されたかを考えながら読み進めてください。
では、スタートです!
善良さん
「よし!ボーナス出たからAmason
でお買い物!」
善良さん
「ログイン完了」
善良さん
「これ買っちゃう(ポチっ)」
善良さん
「これも買っちゃう(ポチっ)」
善良さん
「こっちもこっちも買っちゃう(ポチっ)」
(以下繰り返し)
善良さん
「ふー、カートいっぱいになっちゃった。そろそろ注文しよ」
善良さん
「はい、注文完了届くの楽しみ〜。」
善良さん
「あっ、そうだ。このあいだ教えてもらったサイトで大好きなロックバンドの情報をチェックしとかなきゃ」
(サイト移動)
善良さん
「ふむふむ・・・えっ、今度ライブあるんだー」
善良さん
「どこでどこで」
善良さん
(ポチっ)
・・・
悪徳くん
「はい。善良さん、アウトー」
「うっしっし!」
どこが問題だったのか
正直言って、先ほどのようなことは普通にやってますよね。
でも、このストーリーでは最悪の場合、勝手に注文されてしまったり、アカウントを乗っ取らてしまう危険性もあります。
ただ、実はこの場合でも善良さんが「あること」さえやっていればCSRF
攻撃は実行できませんでした。
それは何かというと・・・
ログアウト
です。
もしかするとお気づきだったかもしれませんが、善良さんは注文をした後、ログアウトせずに別サイトへ移動しています。
そして、その移動先のサイトが「悪いサイト」だったら、ボタンをクリックするだけで、Amason
に「どんなデータでも」送信が可能になります。
なぜなら・・・・・・
善良さんはまだAmasonにはログイン中ですから。
そうです。
例えば、さっき善良さんが「悪いサイト」でクリックしたこのボタン。
実はこれが、以下のようなデータ送信フォームだったらどうでしょう。
<form method="POST" action="(Amasonのログイン情報を変更するURL)">
<!-- 必要なデータはいくつでも追加できます -->
<input type="hidden" name="email" value="(悪徳くんのメールアドレス)">
<input type="hidden" name="password" value="(悪徳くんのパスワード)">
<input type="submit" value="ライブ情報の詳細をチェックする!">
</form>
ブラウザに表示されているのは単なるボタンですが、実はこれをクリックすると善良さんはログイン情報を(自分自身で)変更してしまうことになるかもしれないのです。
つまり、攻撃者は「どのサイトにどんな情報を送れば、何ができるのか」を把握して攻撃を仕掛けてくるわけですね。
特に「無料でファイルをダウンロードできるよ」とか「今ならライブ・チケットが当選確実になります」とか言葉巧みにクリックを誘うわけです。
「うっしっし!」
これがCSRF
攻撃のシンプルな例です。
では、どうすれば防げるのか
では、先ほどの例でいうとAmason
はどんな対策をとっていればCSRF
攻撃を防ぐことができたのでしょう。
それが、Laravel
でも機能を提供している
CSRFトークン(ワンタイムパスワード)
です。
Laravel
では、CSRFトークンが発行された時点でセッションにも内容が保存されます。(つまり、同じデータを訪問ユーザーとLaravelの2者が持つことになります)
そして、フォーム送信する際はこのトークンも一緒に送信し、移動先のページで保存されたトークンと一致しているかをチェックします。
つまり、流れでいうと以下のようになります。
- フォームに入力 ・・・ トークン発行&セッションにも内容を保存
- フォーム送信 ・・・ 発行されたトークンも一緒に送信
- 移動先のページ ・・・ 送信されてきたトークンとセッションのトークンが一致するかチェック
では、これを実行するとなぜCSRF
攻撃を防ぐことができるかというと・・・
トークンをチェックすることで、
データ送信されたページ(送信元)が自分のサイトで間違いないことが分かる
からです。
これが、先ほどの「悪いサイト」だったらどうでしょうか。
もちろんCSRF
トークンを勝手に作ることはできますが、Laravel
のセッションにこの内容を保存することはできません。
つまり、結果としてトークンのチェックをくぐり抜けることはできないというわけですね。
これで一見落着です。
※ ただし今回の例はとてもシンプルな例だということを忘れないようにしてください。攻撃者はより巧みなテクニックを駆使してくることが考えられます。
ちなみに
今回の記事はCSRF
対策がいかに重要かということを知ってもらうために作成したものです。絶対に悪用はしないでください。
おわりに
ということで、今回はいつものプログラム実例ではなくセキュリティ情報についての記事をお届けしました。
正直なところ、需要があるのかどうかは未知数ですが、これからも(たまには)こういった記事をお届けできればと考えています。
ぜひCSRF
対策について理解を深めていただけると嬉しいです。
ではでは〜!