脆弱性診断員だった私がIDORを作り込んだ話
脆弱性診断員だった私がIDORを作り込んだ話
はじめに
私はWebアプリケーションの脆弱性診断員を約10年経験した後、エンジニアに転職して2年が経ちます。
フロントエンド、バックエンド、インフラと幅広く担当しています。
「脆弱性診断員ならセキュアなコードが書けそう」と思う方もいるかもしれません。
私もそう思っていましたが、現実は違いました。
開発業務を始めて半年ほど経った頃、自分のコードにIDOR(認可制御の不備)を作り込んでしまいました。
自分で気づくことができましたが、「今まで指摘する側だったのに」というのが余計に恥ずかしかったです。
IDOR(認可制御の不備)とは
IDORとは、URLやパラメータの値を操作することで、本来アクセスできないリソースにアクセスできてしまう脆弱性です。
例えば、/mypage?user_id=123 というURLの 123 を 124 に書き換えたとき、別ユーザーのマイページが表示されてしまうようなケースが典型です。
認可チェックが適切に行われていないと発生します。
脆弱性診断では比較的よく見かける脆弱性で、URLやリクエストパラメータを少し操作するだけで確認できることが多いです。
診断員時代のIDOR指摘
脆弱性診断ではブラックボックステストが基本です。
ソースコードは見ません。動作しているアプリケーションに対して操作したリクエストを送り、挙動から脆弱性を判断します。
IDORの指摘自体は何度か指摘・報告してきました。
URLやパラメータを操作して他ユーザのデータが取得できる、というパターンです。
ただ、対策として書くのはいつも「セッションに紐づけて認可チェックを行ってください」といったような一般的な内容でした。
ブラックボックスなので実装の詳細は分からない。それが診断員としての前提でした。
正直なところ、その対策がコードレベルでどう実装されるのか、あまりイメージできていませんでした。
個人でプログラミングの経験はありましたが、プロダクトのコードベースで認可がどう設計されるかは別の話です。
やらかしの瞬間
エンジニアになって半年ほど経ったころ、あるページの実装をしていました。
実装が終わりプルリクエストを作成した後に、ふとURLのパラメータを操作してみました。
これはパラメータになにかのIDのような値があれば触ってしまいたくなる診断員のクセなのだと思います。
対象は/group/:groupId/:userId という形のURLで、指定されたグループに配下のユーザ情報を閲覧するエンドポイントでした。
userId の値を別のグループに属しているユーザのIDに変えてみると、本来は閲覧できない別グループのユーザ情報が表示されてしまいました。
「あ、やってしまった」と思いました。
診断員時代に指摘してきた脆弱性を、自分のコードに作り込んでしまいました。
なぜ起きたのか
調べると、コードベースには既存のセキュリティ機構がありました。
このプロダクトでは、エンドポイントに入る前にセキュリティチェック用の関数を通る設計になっていました。
その関数は /group/:groupId/user/:userId というURL構造を前提としており、そのセッションのユーザが閲覧できる情報であるか自動的に検証する仕組みです。
私が実装したエンドポイントはこの構造になっていなかったため、チェックが適用されていませんでした。
私が事前にこの仕組みを把握しておけばよかったという話になりそうですが、それは本質的な問題ではないとも思っています。
実装中に「このパラメータ、別のユーザーの値が来たらどこで弾かれるんだろう」という観点を持っていれば、既存の認可の仕組みに気づけたはずです。
動くことだけを考えて実装していた自分に、その視点がありませんでした。
振り返って思うこと
今回の脆弱性の作り込みには、2つの要因があったと思っています。
1. 実装中は「動くこと」しか考えていなかった
診断員時代にIDORを指摘しながら、実装中はセキュリティ機構の存在を意識していませんでした。
新しいエンドポイントを追加するとき、「既存の認可の仕組みは適用されているか」という視点が抜けていました。
2. 内部実装のイメージが薄いまま診断していた
診断員時代、「セッションのユーザ情報と紐づけて管理してください」と書きながら、それがコードレベルでどう実現されるかをあまりイメージできていませんでした。
そのため、今書いているコードの危険性を察知できませんでした。
また、ブラックボックスだからしょうがないよね、と思っていましたが、サンプルコードや設定ファイル、DBの構造などを通じて「アプリケーションの内部がどう動くか」を日頃からイメージする習慣があれば、診断の精度も上がっていたのではないかと思います。
この経験から変えたこと
この件以来、新しいエンドポイントやパラメータを実装するとき、データの流れを意識的に追うようにしました。
フロントエンドでリクエストを受け取り、どんなバリデーションがかかっているか。
その値がバックエンドでどう処理され、最終的にSQLにどう渡されるか。
もし別のユーザーの値が来たとき、どこで弾かれるのか。
コードを書きながら、この経路を頭の中でトレースする習慣です。
実装の観点がひとつ増えただけですが、セキュリティ機構の見落としはかなり減った実感があります。
これらのことは「車に乗ったらシートベルトを締める」くらい当たり前のことかもしれませんが、診断員時代に「なんでこんな脆弱性を作り込んでいるんだろう・・」という疑問がこの経験を通して少しわかった気がしました。
おわりに
「診断員ならセキュアなコードを書けるはず」という先入観は、少なくとも私には当てはまりませんでした。
診断員としての経験は確かに活きています。自分で実装したコードのパラメータを操作してIDORを発見できたのも、その経験があったからです。
でも、セキュアなコードを書くための実装の勘所は、コードを書き続けることでしか身につかないものがあると実感しています。
診断員もエンジニアも、お互いの視点を持つことが、より良いセキュリティにつながるのかもしれません。
Discussion