脆弱性診断を外部委託したときの手順をまとめてみる
はじめに
株式会社 MICINでエンジニアをしている mimu-salon です。
この記事は MICIN Advent Calendar 2024 の 13 日目の記事です。
前回は Kento Sasaki さんの『モーダルをどのように使うべきか』でした。
この記事では、私が所属しているチームが開発している Web アプリケーションの脆弱性診断を外部に委託したときに気づいた点をまとめたいと思います。
同じような状況の方のヒントになれば嬉しいです。
前提として以下の状況です。
- 自分は脆弱性診断の実施者ではなく、依頼する側の Web アプリケーション(以下、プロダクト)を開発するエンジニアである。
- プロダクトは概ね 5 人から 10 人程度のエンジニアが関わっており、外部委託するために自分が脆弱性診断の窓口担当になった。
色々な実施方法があると思いますが、一例としてご紹介します。
準備段階ですること
今回は完全なブラックボックス診断ではなく、一部のプロダクト情報を実施者に提供しました。
具体的には、主にバックエンド側でのスキーマやエンドポイントをもとに、プロダクト上の実行処理をリスト化したスプレッドシートを用意しました。
提供資料を作成するにあたり、まず最初に行うことは、プロダクトの中で診断範囲を明確にすることでした。
プロダクトは今回初めての診断ではなく、過去にも診断実績があったため、全てが診断範囲ではなく範囲を選定する必要がありました。
また、少しややこしいことに、実施したときはプロダクトが REST から GraphQL への移行期で混在する形でした。
あくまで例示ですが、おおよそ以下のような形でリスト化しました。
REST の場合:エンドポイントごとに分ける。
対象 | Verb | URI | Controller#action | 発生方法 |
---|---|---|---|---|
対象 | GET | /users | UsersController#index | マイページ画面に遷移する |
対象 | POST | /users | UsersController#create | ユーザー登録ボタン押下 |
対象外 | GET | /orders | OrdersController#index | 注文画面に遷移する |
対象 | PUT | /orders/{id} | OrdersController#update | 注文更新ボタン押下 |
対象外 | DELETE | /orders/{id} | OrdersController#destroy | 注文削除ボタン押下 |
GraphQL の場合:Query と Mutation でそれぞれ分ける。
対象 | 概要 | 発生方法 |
---|---|---|
対象 | Query: getUsers | マイページ画面に遷移する |
対象外 | Query: getOrders | 注文画面に遷移する |
対象 | Mutation: createUser | ユーザー登録ボタン押下 |
対象 | Mutation: updateUser | ユーザー更新ボタン押下 |
対象外 | Mutation: deleteUser | ユーザー削除ボタン押下 |
依頼者側の開発チーム内でダブルチェックをしながら、対象と対象外を決めていきました。
優先順位の高い項目は、直近で大きな開発の手が入った箇所や、使用するユーザーが多い機能の関連箇所としました。一方でその逆は、リソースの関係で対象外にする項目もありました。
必ずすべきだと思ったことは、一度プロダクト内のすべて機能を洗い出してから、対象外も記載することです(実際のスプレッドシートでは対象外の行はグレーアウトにしていました)。
見える化に役立つのはもちろんですが、(本来あるべきではないですが)実は使われていないコードがあったりすることを知るためです。
また、脆弱性診断用に検証環境を用意しましたが、併せて推奨ブラウザ(例: Google Chrome、Firefox、Safari など)の案内は事前にすべきです。この情報を共有することで不要な混乱を防ぐことができます。
これは反省点ですが、実施したときは推奨ブラウザを案内しておらず、診断中に実施者が非対応のブラウザを使用していたことで、微妙な挙動の違いが報告されて調査に手間取ったので次回は気をつけたいところです。
実施中にすること
準備段階で必要な情報を提供して、実施中は「何もしなくてよい」が理想ですが、外部の脆弱性診断の実行者がプロダクトの仕様を深く理解していない場合、診断中にサポート依頼を受けることが多くあります。大別すると以下の 2 点です。
診断用アカウントの作成と権限付与
診断期間中、頻繁にテスト用のアカウントや関連するレコードの作成を依頼されました。診断の実施者が特定の権限や状態でテストを行いたい場合に応じて、指示された必要な数のアカウントを作成しました。
プロダクトの操作のみだと数が多く煩雑になるので、作業時間を短縮するために簡易的なスクリプトを作成して対応しました。
診断者だけで完結しない操作のサポート
診断の実施者だけで完結しない処理がある場合、その都度やりとりが発生するので、円滑な実施を阻害してしまい両者にとって負担になります。
できるだけ軽減するように工夫したいところです。例えば実際にあったことは、プロダクトの一部の通知機能で社内のみで使用する Slack チャンネルに通知が飛ぶフローがあり、通知結果を共有するためだけにやりとりが発生してしまう問題がありました。これを解決するために脆弱性診断用の検証環境に限り、これを診断の実施者とやりとりしている別の Slack チャンネルに通知先を一時的に切り替えて、診断の実施者だけで一連の操作が完結できるようにしました。
しかしながら、特定のトリガーが別プロダクトの管理ツールの操作を必要とする場合など、診断の実施者だけで操作を完結させるのが難しいケースはどうしても発生するので、適宜サポートする必要がありました。
実施後にすること
診断結果はテキストで受領して、速やかにプロダクトの開発チームに共有しました。当然ですが、もし危険度の高い脆弱性が検出された場合には早急に対策を検討すべきです。幸い実施時は危険度の高い脆弱性は検出されませんでした。ただし、危険度が低い箇所も含めて、指摘事項は多くの場合に挙がってくるはずなので、推奨される対策を一通り確認します。
経験談ですが、普段開発をしているプロダクトの診断結果を見ると、臨場感を持って問題意識が湧いてきます。初歩的なところだと、フロントエンド側だけにバリデーションを任せず、きちんとバックエンド側のバリデーションを意識しないと、簡単にデータの改ざんの標的になってしまうなど、堅牢にするべくコードを書くために、普段の開発を見直すきっかけになります。
おわりに
Web アプリケーションにとってセキュリティは重要で、ある程度の規模の Web アプリケーションであれば、定期的に脆弱性診断は実施されます。
依頼者と実施者がコミュニケーションをとり、円滑な診断実施を進めたいというのは多くの場合に当てはまると思うので、この記事でまとめたことが一助になることを願っています。
MICINではメンバーを大募集しています。
「とりあえず話を聞いてみたい」でも大歓迎ですので、お気軽にご応募ください!
Discussion