SecretlintというAPIトークンなどの機密情報がファイル内に含まれているかをチェックできるツールを書いています。 Secretlintはコマンドラインツールとして動くので、主にCIやGitのpre-commit hookを利用して、リポジトリに機密情報が入るのを防止できます。

一方で、実際のウェブサービスなどは機密情報がファイルにハードコードされているわけではなく(Secrelint自体がこういうハードコードを防ぐツールです)、環境変数やDatabaseに保存していると思います。

このような場合にも、コードのミスなどによって公開するべきではない情報(秘密鍵、APIトークン、SlackのIncoming WebHook URLなど)が、APIレスポンスやレンダリングされたHTMLにJSONとして埋め込まれてしまうような一種の事故をたまに見かけます。 (本来はサーバからAPIトークンを使って叩くべきところを、フロントから叩くような実装になってしまっているケースなども同様です)

公開してしまうと問題ある情報は、パスワードやAPIトークンのような機密情報だけではなく、本来出すべきではなかった個人情報(IPアドレス、氏名など)も含まれるため結構複雑です。

いつも見ているサイトに、表示はされていないが公開するべきではない情報がHTMLやAPIのレスポンスに入っているイメージです。 これらの情報は実際には表示されないので、漏れていることに気づきにくいという特徴もあります。 また、脆弱性診断をするセキュリティの専門家が見ても、その情報が意図的に公開されているのかはコンテキストに依存するので判断しにくいという特徴もあります。

これらの情報が意図せず公開されているかを判断できるのはそれを作っているウェブエンジニアなので、 ウェブエンジニアがよく使うデバッグツールであるブラウザの開発ツールにSecretlintを組み込むSecretlint WebExtensionを作りました。

📝 意図せずに公開されているのが問題となる情報を見つけるのが目的のブラウザ拡張機能です。secretlintの判定処理はJavaScriptで書かれているので、拡張の内部でのみ処理されます。ソースコードをGitHubで公開しているので、ソースコードからビルドして利用もできます。

Secretlint WebExtension

Secretlint WebExtensionは、Secretlintをブラウザ上で動かして、リクエストとレスポンスに含まれている機密情報や問題ありそうなパターンを検知するブラウザ拡張です。

デフォルトで、GitHub/Slack/SendGrid/GCP/AWS/秘密鍵などのパターンを判定する@secretlint/secretlint-rule-preset-recommendとIPアドレスやAuthorization Bearerのヘッダなどをヒューリスティックに検知するルールが含まれています。

ブラウザの開発者ツールを拡張して、"Secretlint"パネルに見つけた機密情報を表示します。 また、コンソールに同時に見つけた機密情報をログとして表示するオプションもあります。

Secretlint WebExtension

Permissions

2021-08-20時点で、この拡張が利用するPermissionsは次の通りです。

  • "<all_urls>"
    • devtools APIと"Console Integration"のため利用しています
    • 実際には、ブラウザの開発者ツールを開いて見ているページにおいてのみチェックされます
    • 開発者ツールを開かずに見ているページは、リクエスト/レスポンスのチェックはされません
    • 開発者ツールを開いているときのみ動作するのは、devtools APIを利用しているため仕様です
  • "webNavigation"
    • ページの移動したを際に"Secretlint"パネルのログをクリアするために利用しています
    • 開発者ツールの独自パネル("Secretlint"パネル)に描画した内容は自動では消えないため、ページを移動した場合に表示されてるログをリセットするために利用します
  • "storage"
    • 拡張の設定情報を保存するために利用しています

📝 devtools APIを利用するためには、Host Permissionsと呼ばれるcontent_scriptsなどを動かすための権限が必要となるようです。 開発者ツールはどのページでも開けるため、このような仕様になってるのかもしれません(アクション起因じゃないからかactiveTabでは動きませんでした)。

インストール

FirefoxとChromeでそれぞれストアからインストールできます。

使い方

Secretlint WebExtensionは、次の手順でチェックでリクエストとレスポンスに含まれる機密情報をチェックできます。

  1. ブラウザの"開発者ツール"を開きます
  2. ✅ Disable Cache が有効になっていることを確認します
  3. ページをリロードすると、"Secretlint"パネルに見つけた機密情報を表示します
    • "Enable Console Integration" が有効時は"Console"パネルにも表示します

実際にどのように表示されるかは、次のサイトに色々な機密情報を埋め込んだページを用意してあるので確認できます。

設定で無視したいパターン(Allow Patterns)と見つけたいパターン(Disallow Patterns)が定義できます。 詳しくはREADMEを見てみてください。

技術的なこと

Secretlint WebExtensionのソースコードはGitHubに公開しています。 READMEにはビルド方法も書いてあるので、自分で拡張をビルドして利用もできます。

textlintの経験もあって、Secretlint自体が最初からモジュールが細かく別れていて、コアやルールはブラウザでも動くように書かれていました。 そのため、webpackなどでまとめるだけで動いたので特別なことはしていません。

ブラウザ拡張の開発はウェブ開発と違って気が利いたツールが少ないので面倒くさいですが、Secretlint WebExtensionWebExtension Toolboxを使っています。 Manifest v3への対応がいまいちだったりしますが、Create React Appみたいな感覚で使えるのでボイラープレートが少なくてすみます。(Viteベースとかで同等のツールが出てくれるといいのだけど)

なぜ開発者ツールに組み込んだかは、Motivationにも書いています。 セキュリティ研究者などはBurp SuiteといったProxyアプリを使ってリクエスト/レスポンスを見ると思いますが、 ウェブアプリの開発者はだいたいが開発者ツールで完結しているので、ウェブアプリの開発者が使うツールをイメージしたら開発者ツールに組み込むのが良いと思いました。

一方でデザインとかはほぼ何もしてないReactで書いたUIなので、その辺を改善してくれる人を待っています!

Secretlintと違ってSecretlint WebExtensionは見つけることが主な目的なので、少しヒューリスティックな過剰検知しやすいパターンも含んでいます。 この辺はもっと改善できると良い気がします。良いアイデアがあってIssueを作ってください。

Codecovの問題からSecretlintで個人情報の検知もやりたかったけど、GCPのDLPもfalse positiveがかなり多いので、あんまりモチベーションがなくてやれてなかったです。

しかし、Secretlint WebExtensionならこういった誤検知が表示されても、そこまで大きく問題にならない(CIで動かすツールと人間向けのチェックツールの違い)ので、DLP的なものをオプションで実装してみるのも面白そうだなーと思いました。