外から攻めて検査する② ── 攻撃ツールと正規ツールで、見つかるものは違う

上原正吉(EarthLink Network Co., Ltd.)。AI会社・AI社員による業務自動化と、人の逐次介入なしに24時間自動開発を回す仕組みを自社で実践しています。開発ノウハウと具体的な設定方法、運用して分かった改善点を公開しています。

外から攻めて検査する② ── 攻撃ツールと正規ツールで、見つかるものは違う

外から攻めて検査する② ── 攻撃ツールと正規ツールで、見つかるものは違う

この記事は、連載「自分のサービスは自分で守る ── AI 時代の自衛セキュリティ」の第 5 回です。自分でできる検査は自分で、難しいときは EarthLink Network が検査を代行し、直せない弱点は私たちが修正します。

連載の目次

  1. AIで誰でも攻撃できる時代 ── やられる前に、自分のサイトを自分で検査する
  2. 攻撃する側が持っているツール ── AI が自分で攻撃を進めるとは
  3. 検査を始める前に ── 検査の全体像と、本番を壊さない線引き
  4. 外から攻めて検査する① ── 準備と、最初の実行まで
  5. 外から攻めて検査する② ── 攻撃ツールと正規ツールで、見つかるものは違う(この記事)
  6. 自分の書いたコードを検査する ── 静的解析(予定)
  7. 使っている部品の弱点を検査する ── 依存ライブラリ(予定)
  8. インフラの設定の誤りを検査する(予定)
  9. 検査の結果を 1 か所に集めて、どれから直すかを決める(予定)
  10. 見つかった弱点の直し方 ── 3 つの道(予定)
  11. 自分で直せないときは ── 保守契約という選択(予定)
  12. 毎日自動で検査し続ける ── 作る時代から、守り続ける時代へ(予定)

結論

前回は、自分のサービスのコピーを用意して、検査のツールを実際に動かすところまでをお見せしました。攻撃する側が使うツールと、正規のツールの両方です。今回は、そのときに出てきた結果を、ツールごとに並べて分析します。外から試すツールの結果を正しく評価するには、コードを読むツールの結果と並べるのがいちばん分かりやすいので、今回は両方を比べます。コードを読む検査そのもののやり方は、次の第 6 回で扱います。

先に結論を書きます。見つかる弱点の「種類」は、ツールによって違いました。外から試すツールにしか見えないものがあり、コードを読むツールにしか見えないものがあります。だから、どれか一つでは足りません。

もう一つ、大事な違いがありました。攻撃する側のツールは、安い AI で動かして、たった 3 セントで弱点の候補を 6 件挙げました。ところが、確かめると本物は 2 件だけで、残りの 4 件は誤報でした。一方、今回同じコピーに実行した正規のツール 3 つ(Strix・ZAP・StackHawk)は、どれも誤報を出しませんでした。値段の差ではありません。正規のツールにも無料のものがあります。今回の実験で目立った違いは、挙げた候補を自分で確かめ直す手順があるかどうか、でした(ただし、相手にした環境も違いました)。

今回は、この順に見ていきます。

  1. 前回動かした検査ツールを、もう一度並べる
  2. 機械は「念のため」で挙げ、そして自分で絞る
  3. 攻撃する側のツールの 6 件のうち、4 件は誤報だった
  4. コードを読む正規のツールは、別のものを見つけた
  5. 本物は、実際のコードと、再現かコードの流れで確かめる
  6. 無いことも、証明して取り下げる
  7. 並べると、見つかるものの種類が違う
  8. 外から試す正規のツールの結果
  9. 調べ方・ツールの出どころ・AI の有無を、分けて見る
  10. 費用は、差にならなかった
  11. 本物か誤報かを見分ける、三つの観点
  12. 本物も、無いことの証明も、両方を正しく受け取る
  13. だから、集めて仕分ける手順が要る

検査の相手は、前回と同じく、自分のサービス(promptflow)の、ログイン周りの処理を写した使い捨てのコピーです。本番のサービスにも、他人のサイトにも、一切触れていません。

前回動かした検査ツールを、もう一度並べる

前回、同じ自分のサービスのコピーに、次の検査ツールを実行しました。名前は、それぞれの種類の例として覚えてもらえば十分です。

ツール調べ方ツールの出どころAI実行日
Strixコードを読む正規(許可された検査のため)安い AI(DeepSeek)2026-10-20
HexStrike外から試す攻撃する側(使い方の制限なし)安い AI(DeepSeek)2026-10-20
ZAP外から試す正規(無料で公開されている)なし2026-10-22
StackHawk外から試す正規(商用・14 日間の無料お試し)なし2026-10-22

表を見ると分かるとおり、ここには三つの別々の違いが混ざっています。一つは、コードを読むか、外から試すか、という調べ方の違い。もう一つは、正規のツールか、攻撃する側のツールか、という出どころの違い。そして、AI が動かしているかどうか、の違いです。この三つを混ぜたまま比べると、何が差を生んだのかを取り違えます。今回は、最後にこの三つを分けて並べます。

機械は「念のため」で挙げ、そして自分で絞る

検査ツールの結果を初めて見ると、たいてい驚きます。「怪しい」とされた候補が、ずらりと並ぶからです。これを見て、「うちのサービスは弱点だらけだ」と青ざめる必要はありません。機械は、確実に危ないものだけでなく、「もしかしたら危ないかもしれない」というものまで、念のため全部挙げるようにできているからです。本当に危ないものを一つ見逃せばそこから入られますが、問題ないものを間違って挙げても、確かめて外せば済みます。だから、挙げすぎるように作ってあります。

ここで大事なのが、まともなツールは挙げっぱなしにしない、という点です。候補を一つ挙げるたびに、わざと「これは本当は問題ないのではないか」という逆の証拠を探し、実際に再現できるかを自分で試します。直す前のコードに対してわざと試して、「本当に起きる」ことも確かめます。再現できたもの、または動かせない部分はコードの流れを端から端まで追って示せたものだけを本物として残し、できなかったものは誤報として取り下げます。

候補から本物へ絞り込む流れ。コードを読む検査ツール(Strix)は、三つの観点(トークンとセッション・アクセスの制御・秘密)で候補をたくさん挙げ、一つずつ反証を試み、相手役を使って実際の処理を動かし、直す前のコードでの対照の実行もするか、コードの流れを端から端まで追う。示せなかったものは取り下げ、示せたものだけを本物として残す。今回は 3 件が残った(2 件は再現・1 件はコードの流れ)。2026-10-20 の実行の記録から作った図。

なぜ機械は、そもそも勘違いするのか。機械は、文字の形や、書かれている場所のパターンで候補を拾います。たとえば「長い英数字の文字列があれば、秘密の鍵かもしれない」というふうに。でも、長い文字列が全部、秘密の鍵とは限りません。公開してよい識別子も、ただのリンクも、長い英数字の形をしています。形で拾うところまでが機械の得意なことで、意味で見極めるところは、確かめ直す手順か、人の目が要ります。

この「確かめ直す手順」があるかどうかで、結果がどれだけ変わるか。それを、今回の二つの安い AI のツールが、はっきり見せてくれました。

攻撃する側のツールの 6 件のうち、4 件は誤報だった

まず、外から試す、攻撃する側のツール(HexStrike)の結果です。前回お見せしたとおり、安い AI が自分で次の一手を決めながら進み、私たちが決めた上限の 24 手(24 回の操作)に達したところで、終わる前に打ち切られました。挙げた候補は 6 件。深刻なものが 2 件、高いものが 2 件、中くらいが 1 件、低いものが 1 件です。実費は約 3 セント(0.0331 ドル)でした。

この 6 件を、一つずつ確かめました。結果がこれです。

攻撃する側のツール(HexStrike)が挙げた6件を、本物か誤報かで仕分けた表。本物は2件。応答のヘッダの欠け(動いている応答そのもので確認できた)と、ログアウトの挙動の一部。誤報は4件。「どんなコードでもトークンを出す」「同じトークンを何度も使える」「rt_で始まる文字列なら何でも受け付ける」の三つは、身元確認の代わりに置いた簡易版サーバの甘さによるもので、製品のコードの弱点ではない。残る一つは、テストそのものがおかしなリクエストを送って起きた見せかけ。2026-10-20 の実行の記録から作った表。

なぜ誤報が出たのか。

検査される側は、自分のサービスのコード本体をそのまま写したものです。ここは本物です。ただ、ログインの相手になる「身元確認のサーバ」と、記録の保存先だけは、本番そのものではなく、簡易版を手元に置きました。本番から切り離した専用の環境でコピーを動かすには、相手役が要るからです。

この簡易版のサーバが、とても甘く作ってありました。たとえば、どんな値を送ってもトークン(ログインしたことを示す、通行証のような文字列)を返してしまいます。攻撃する側のツールは、それを見て「どんなコードでもトークンが出る、これは重大な入り込みだ」と、自信たっぷりに報告しました。

でも、これは製品のコードの弱点ではありません。甘いのは、相手役として置いた簡易版のサーバのほうです。本番では、ここはきちんと確認する作りになっています。

同じ甘さは、別のところにも出ました。トークンを更新する処理に、でたらめな文字列を送ってみます。「totally-made-up-xyz」のような文字列は、きちんと拒まれました。ところが、「rt_」という三文字で始めた文字列は、中身がでたらめでも通ってしまいました。簡易版のサーバが、文字列の中身ではなく、先頭の三文字だけを見ていたのです。ツールは、これも「重大な入り込み」として報告しました。けれど、これも相手役の作りによるもので、本番のコードの弱点ではありません。

誤報 4 件のうち 3 件は、この簡易版サーバの甘さが原因でした。残る 1 件は、検査の仕組みそのものがおかしなリクエストを送ってしまって起きた見せかけでした。正しい形で送り直すと、ログアウトはきちんと成功を返しました。

ここを曖昧にしてはいけません。簡易版の甘さを「製品の弱点」として記録してしまうと、ありもしない情報漏れを、自分ででっち上げることになります。それは、この連載がいちばんやってはいけないと言ってきたことです。だから、4 件は誤報として、はっきり取り下げました。

本物だった 2 件のうちの一つ、応答のヘッダの欠けは、外から試すツールだからこそ見つけられたものです。ヘッダとは、ブラウザに「この表示を他のサイトに埋め込ませない」「通信は必ず暗号化する」といった約束事を伝える、小さな設定のことです。動いているサービスの応答を実際に受け取らないと、欠けているかどうかが分かりません。もう一つのログアウトの件は、次に見るコードを読むツールも見つけていた弱点と、同じ原因のものでした。

私たちが組んだこのツールの動かし方には、候補を挙げたあと、それを自分で確かめ直す手順がありませんでした。試して、反応を見て、「入り込める」と思ったら、そのまま報告します。確かめ直す手順が無いと、本物と一緒に誤報もそのまま報告に残ります。

コードを読む正規のツールは、別のものを見つけた

次に、コードを読む正規のツール(Strix)です。こちらは、動いているサービスを外から試すのではなく、サービスのコード本体を読みます。動かした AI は、攻撃する側のツールと同じ安い AI(DeepSeek)です。

まず、このツールが候補を自分で取り下げる様子を、実際の画面で見てください。これは、本番の 3 件を出した実行の前日(2026-10-19)に、同じログイン周りのコードに試したときの画面です。費用の上限を 1 ドルにした、試しの実行でした。

コードを読む正規ツール(Strix)の実際の画面。2026-10-19、ログイン周りのコードのコピーに試しで実行したもの。画面の中ほどに「Two of the specialists' own findings did not survive my review, and I had both withdrawn(担当が挙げた候補のうち2件は、確かめ直した結果、取り下げた)」とあり、時間差を使った推測と、外部からの読み込みの許可の設定の2件を、根拠を示して取り下げている。その上には「CSRF(ほかのサイトから、本人のつもりの操作を送らせる攻撃)・注入・/me の入口の操作は起こせないと確かめた」という報告もある。

画面の中ほどに、「担当が挙げた候補のうち 2 件は、確かめ直した結果、取り下げた」と書いてあります。一つは、応答にかかる時間の差から中身を推し量れるのではないか、という候補。もう一つは、外部のサイトからの読み込みを許す設定が甘いのではないか、という候補です。どちらも、なぜ違うのかを示したうえで、取り下げています。攻撃する側のツールにはなかった、確かめ直す手順が、ここにあります。

そして翌日(2026-10-20)、範囲をログイン周りの 4 つの入口にしぼって実行した結果が、これです。ツールが書き出した結果のファイルを、そのまま表示した画面です。

Strix が書き出した結果のファイル(vulnerabilities.csv)を、中身を変えずにブラウザに表示した画面。2026-10-20 の実行。vuln-0002「確かめていない身元の情報で監査の記録を書いている」は MEDIUM、vuln-0003「トークンの断片と相手のエラー文をサーバの記録に書いている」は MEDIUM、vuln-0001「ログアウトが成功と答え、成功の記録を書くのに、サーバ側のセッションは生きたまま」は INFO。

見つかったのは 3 件。誤報は 0 件でした。重さは、中くらい(MEDIUM)が 2 件、情報(INFO)が 1 件です。この重さは結果のファイルの値で、ログアウトの件は、同じ実行の報告書の本文では中くらいとして書かれています。

  • ログアウトが、成功したと答えるのに、実際にはサーバ側のセッション(ログインしている状態)を終わらせていない(INFO)。
  • 監査の記録を残すとき、確認していない身元の情報をそのまま信じて、記録の「誰が」の欄に使ってしまう。ログインしていない相手が、記録に好きな名前を書き込める(MEDIUM)。
  • トークンの更新に失敗したとき、トークンの先頭部分と長さ、相手から返ってきたエラー文を、そのままサーバの記録に書き出している(MEDIUM)。

二つ目の、監査の記録の身元の件を例に取ります。これは、誰が何をしたかの記録に、確かめていない名前をそのまま書いてしまう、という弱点です。あとで「誰がやったのか」を調べようとしても、記録そのものが信用できなくなります。こういう弱点は、画面を外からいくら触っても見えません。コードの中の、処理の順番を読んで初めて分かります。

このうち二つ目と三つ目は、動いている応答を外から見ても分からない種類の弱点で、外から試すツールは見つけられませんでした。一つ目のログアウトの件は、外から試すツールも挙動の一部をとらえていましたが、簡易版のサーバの振る舞いと混ざって、はっきりしないままでした。

本物は、実際のコードと、再現かコードの流れで確かめる

では、残った本物は、どんな形で手元に届くのか。見つけたと言いっぱなしにせず、どのファイルのどこか、どう再現するか(またはコードの流れ)、までついてきます。3 件のうちの一つを、実際の中身で見てみます。

これは、ログインの鍵を更新する入口で見つかった弱点です。鍵の更新に失敗したとき、受け取った鍵の最初の 12 文字と長さ、相手から返ってきたエラー文を、そのままサーバの記録に書いていました。問題なのは、すぐ上の行に「鍵は記録に書くな」という注意書きがあるのに、その二行下で書いていたことです。意図と、実際のコードが食い違っていたわけです。

確定した弱点の一つ。鍵の更新に失敗したときの処理で、「鍵を記録に書くな」という注意書きのすぐ下で、鍵の先頭12文字と長さ、相手のエラー文を記録に書いている。直す前のコードを相手役に対して実際に動かすと、漏れた先頭は rt-SECRETV、長さは 18、相手のエラー文に鍵全体、と漏れが再現した。だから本物(重さは中くらい・MEDIUM)と確定した。2026-10-20 の実行の記録から作った図。

大事なのは、ツールが「記録に鍵を書いている箇所がある」と指摘して終わりにせず、直す前のコードを相手役に対して実際に動かし、本当に漏れることを、相手役(簡易版の相手)の上で再現してみせたことです。再現の記録には、漏れた鍵の先頭(rt-SECRETV)、長さ(18)、相手のエラー文に鍵全体が入っている様子まで、はっきり残っています。「理屈では危ない」ではなく「相手役の上で、実際に漏れた」。ここまで証拠があれば、人の判断は「これは直す」で即決できます。

残りの 2 件も、実際のコードの場所つきでした。ログアウトの件は、同じように相手役を使って再現しています。ログアウトの入口は、ログインの取り消しを相手のサービスに頼む処理を「鍵が二つともそろっていれば」という条件で囲っていて、片方でも欠けると取り消しを飛ばします。しかも、取り消しを頼んだあと、相手が本当に取り消せたかどうかの返事を一度も確かめていません。それなのに、「セッションを消した」という記録と「成功」という返事は、どの場合でも必ず書かれます。相手役を使って 8 通りの送り方を試すと、7 通りで、実際には消えていないのに「消えた」と報告しました。

監査の記録の身元の件は、コードの流れを入口から記録の書き込みまで追って示したものです。ツールは正直に範囲も限っていました。読み取った名前は監査の記録に書かれるだけで、権限の判断や返事の中身には使われていないので、これは「ログインの突破」ではなく「監査の記録が信用できなくなる問題」だ、と。見つけたものを大げさにも控えめにもせず、実際に届く範囲で評価しています。

そして、3 件とも直し方まで示されていました。記録への漏れの件は、鍵の断片と長さと相手のエラー文を消し、代わりに元に戻せない形に変えた短い値と、エラーの種類だけを記録する。ログアウトの件は、相手が本当に取り消せたかの返事を見て、その結果を記録と返事に反映する。監査の身元の件は、署名を確かめた値が取れるまでは固定の仮の名前を書き、外から来た確かめていない名前は使わない。どれも、小さく、その場所だけの直しで済みます。直し方は、第 10 回でくわしく扱います。

無いことも、証明して取り下げる

結果を分析するうえで、同じくらい大事なのが、ツールが「無い」と言い切った部分です。検査の値打ちは、弱点を見つけることだけではありません。「ここには、この種の危険は無い」と、根拠つきで取り下げられることも、同じくらい大事です。無いと分かれば、そこに気をもまなくて済むからです。

無いことの証明。注入(データベースへの命令やコマンドの差し込み)は、データベースにつなぐ部品も外部コマンドを動かす仕組みもこの範囲に無いので起こせない。SSRF(サーバをだまして別の場所へ通信させること)は、外へ出ていく通信先がすべて固定の設定値なので起こせない。コードの中の秘密の値は、外へ送る処理の中だけで使われ、記録や返事には出ていかない。安全でない署名付きのリンクは、それを作る部品自体が無い。いずれも構造上あり得ないと示された。2026-10-20 の実行の報告から作った図。

「まだ見つかっていない」と「構造上あり得ない」は、まったく違います。前者は、ただ見落としているだけかもしれません。後者は、そこを心配しなくていい、と安心して線を引けます。

外から試すツールにも、似た結果は出ます。たとえば無料の ZAP は、120 の項目を外から試し、データベースへの命令の差し込みやコマンドの差し込みを含む 117 の項目では問題が見つからなかった(PASS)と記録しました。残りの 3 項目は警告です。これはこれで役に立ちますが、言えるのは「試してみて、何も起きなかった」までです。コードを読むツールは、「そもそも起こせる部品が無い」と、理由まで示せます。同じ「無かった」でも、根拠の深さが違います。

警告をただ並べるだけの検査なら、これらは「可能性あり」として人の確認待ちの山に積まれていたでしょう。そのうちの多くが、調べてみれば実害のない誤報です。人がいちばん消耗するのが、この「誤報の山を一つずつ外す」作業でした。確かめ直す手順を持つツールは、その大半を自分で取り下げてくれます。人の手元に残るのは、本物と、本当に判断が要るものだけです。

並べると、見つかるものの種類が違う

ここまでの二つ、コードを読むツールと、外から試す攻撃する側のツールを並べます。

二つのツールの発見を並べた表。ログアウトの偽りの成功、監査の記録の身元の偽装、記録へのトークン断片の漏れは、コードを読む側(Strix)が見つけ、外から試す側(HexStrike)は見えないか、相手役に紛れてはっきりしない。応答のヘッダの欠けは、外から試す側が見つけ、コードを読む側には見えない。注入による乗っ取りは、コードを読む側が「構造上あり得ない」と証明し、外から試す側は試して何も見つけなかった。誤報はコードを読む側が0件、外から試す側は6件中4件。費用はコードを読む側が9分で0.45ドル、外から試す側が24手で0.03ドル。

片方が見つけたものを、もう片方は見られません。コードを読む側は、処理の筋道の間違いや、記録の信頼性、秘密の扱いを見られます。でも、動いている応答のヘッダは見られません。外から試す側は、その逆です。動いている応答のヘッダは見つけますが、コードを読まないので、記録の身元の偽装も、記録への漏れも見えません。

これは、片方のツールの結果を見て「弱点は無かった」と早合点してはいけない、ということでもあります。外から試すツールだけを使えば、記録の身元の偽装や記録への漏れを見落とします。コードを読むツールだけを使えば、応答のヘッダの欠けを見落とします。どちらも、見落としたこと自体に気づけません。見えない範囲を「見えない」と知っておくことが、最初の一歩です。

外から試す正規のツールの結果

ここまでだと、「外から試すツールは誤報が多い」と読めてしまいます。でも、本当にそうでしょうか。外から試すツールにも、正規のものがあります。そこで前回、同じコピーに、外から試す正規のツールを二つ実行しました。無料の ZAP と、商用の StackHawk です。どちらも AI は使っていません。決められた項目を、順番に調べていくツールです。

まず、ZAP が書き出した結果のページです。

ZAP の結果のページの実際の画面(2026-10-22)。危険度ごとのまとめで、高が0件、中が0件、低が3件、情報が3件、誤報(False Positives)が0件。下の一覧には、低として Cross-Origin-Resource-Policy の欠落、想定外の形式の応答、X-Content-Type-Options の欠落が並び、情報として、利用者側のエラー応答などが並ぶ。

危険度のまとめを見てください。高も、中も、0 件です。低が 3 件で、中身は応答のヘッダの欠けが 2 種類と、想定と違う形式の応答が 1 種類。画面の「誤報」の欄は、人が誤報と印を付けた数で、0 件です。私たちが応答を確かめても、ヘッダの欠けは実際に起きていました。注入による乗っ取りのような深刻な種類は、調べたうえで、一件も出ませんでした。

次に、StackHawk です。端末に出た結果の文字がこれです。

StackHawk の検査ツール(HawkScan)を同じコピーに実行したときの、端末に出た結果の文字(2026-10-22)。重大0件・中6件・低13件。見つかったのは、表示の乗っ取りを防ぐヘッダの欠け、表示できる内容を限る設定(CSP)が無いこと、使っている土台(Next.js)の名前が応答に出ていること、X-Content-Type-Options の欠け。いずれも応答のヘッダに関わるもの。端末の記録を、色も含めてそのまま画像にしたもの。

高 0 件・中 6 件・低 13 件。これは見つかった場所の数で、種類で数えると 4 種類です。表示の乗っ取りを防ぐヘッダの欠け、表示できる内容を限る設定が無いこと、使っている土台の名前が応答に出ていること、そしてもう一つのヘッダの欠け。どれも実際の応答で確かめられる本物で、誤報は 0 件でした。

StackHawk には、結果を管理する画面も付いています。

StackHawk の管理画面の実際の画面(2026-10-22)。promptflow-selftest の検査結果として、High 0・Medium 6・Low 13 が並び、その下に見つかった4種類(Missing Anti-clickjacking Header・Content Security Policy (CSP) Header Not Set・Server Leaks Information via "X-Powered-By"・X-Content-Type-Options Header Missing)が、重さと見つかった場所の数とともに一覧になっている。左下には「Free trial ends soon・14 days remaining(無料お試しの残り14日)」と出ている。

見つかったものが重さの順に並び、どの場所で見つかったかが一覧になり、検査ごとに記録が残ります。左下に「無料お試しの残り 14 日」と出ているのが見えると思います。StackHawk には、ずっと無料で使えるプランはありません。最初の 14 日間は無料で試せて、続けて使うなら 1 人あたり月 10 ドルからです(2026 年 10 月 23 日の公式の料金のページ)。今回は、その無料お試しの期間の中で使いました。

外から試す、という調べ方は同じなのに、正規の二つは、自信に満ちた誤報を一つも出しませんでした。見つけたのは、どちらも応答のヘッダの欠けです。攻撃する側のツールが見つけた本物と、同じ種類でした。つまり、外から試すことで見つかる種類のものは、正規のツールでも、ちゃんと見つかります。

調べ方・ツールの出どころ・AI の有無を、分けて見る

ここで、最初に書いた三つの違いを分けて並べます。縦は調べ方(コードを読む・外から試す)。横はツールの出どころ(正規・攻撃する側)。そして、それぞれのツールに、AI が動かしているかどうかの印を付けました。

調べ方・ツールの出どころ・AI の有無を分けて描いた図。縦は調べ方(コードを読む・外から試す)、横はツールの出どころ(正規のツール・攻撃する側のツール)。コードを読む×正規には、AI なしの Semgrep(自分のサービスで毎日、自動で実行・第 6 回で扱う)と、安い AI で動かした Strix(本物3件・誤報0件・0.45ドル)。コードを読む×攻撃する側は、空のマス(攻撃する側は、ふつう相手のコードを持っていない)。外から試す×正規には、AI なしの ZAP(誤報0件・ずっと無料)と StackHawk(誤報0件・14日間の無料お試しの中で0円)。外から試す×攻撃する側には、安い AI で動かした HexStrike(本物2件・誤報4件・0.03ドル・この動かし方では確かめ直さずに報告)。下に「Strix も HexStrike も同じ安い AI で動かした。誤報を出したのは攻撃する側のツールだけで、AI の有無では説明できない。目立った違いは確かめ直す手順の有無。相手にした環境も違い、Strix はコードを読み、HexStrike は簡易版のサーバを相手にした」とある。

こう分けると、三つのことが見えてきます。

一つ目。見つかるものの種類を決めるのは、調べ方です。コードを読むツールは、処理の筋道や記録の信頼性の弱点を見つけ、外から試すツールは、応答のヘッダの欠けを見つけました。出どころが正規でも攻撃する側でも、外から試すツールが見つけたのは同じ種類でした。

二つ目。誤報の数の差は、AI の有無では説明できませんでした。Strix と HexStrike は、同じ安い AI で動かしています。それでも、Strix は誤報 0 件、HexStrike は 6 件中 4 件でした。目立った違いは、挙げた候補を自分で確かめ直す手順があるかどうかです。ただし、Strix はコードだけを読み、HexStrike は簡易版のサーバを相手に動かしたので、相手にした環境も違いました。AI を使っていない ZAP と StackHawk も、決められた項目を規律よく調べるので、誤報は出ませんでした。Strix・ZAP・StackHawk の「誤報 0 件」は、2026 年 10 月 20 日と 22 日に、同じコピーに対して実行した結果です。

三つ目。右上のマスは、空のままです。攻撃する側は、ふつう相手のコードを持っていません。だから攻撃する側は、外から試すしかありません。逆に言えば、自分のコードを読めるのは、守る側だけの強みです。それを使わない手はありません。

左上の Semgrep は、自分のサービスの毎日の自動の検査の中で動いています。どう動かして、何が出てくるのかは、次の第 6 回で実際に動かしてお見せします。

費用は、差にならなかった

費用を、四つ並べます。

四つのツールの費用と誤報。外から試す正規の ZAP は 0 ドルで誤報 0 件、外から試す正規の StackHawk は 14 日間の無料お試しの中で 0 ドル・誤報 0 件、コードを読む正規の Strix は安い AI で 0.45 ドル・誤報 0 件、外から試す攻撃する側の HexStrike は安い AI で 0.03 ドル・6 件中 4 件が誤報。正規は高い、は当てはまらず、四つともほとんど費用がかからない。差が出たのは誤報の数だった。

ZAP はずっと無料、StackHawk は無料お試しの期間の中で 0 円でした。安い AI で動かした二つは、45 セントと 3 セントです。四つのどれにも、特別な機械も、高機能で最新の AI も要りませんでした。

ここが、攻撃する側のこわいところです。特別な技術も、高価な AI も要りません。安い AI を数多く動かして、入口を一つずつ試す。やっていることは、賢さを要する仕事ではなく、根気のいる単純作業です。だからこそ、3 セントで回ってしまいます。

でも、同じことが守る側にも言えます。正規のツールにも ZAP のような無料のものがあり、StackHawk にも 1 人あたり月 10 ドルからの段があります。「正規のツールは高いから、手が出ない」という思い込みは、もう当てはまりません。攻撃する側のツールと正規のツールの差は、値段ではありませんでした。誤報が出るかどうかと、見つかるものの種類です。

本物か誤報かを見分ける、三つの観点

ツールが多くを絞ってくれるとはいえ、最後の見極めは人がします。私は、三つの観点で確かめています。

  1. それは、本当に秘密の情報か、本当に間違った振る舞いか。鍵やパスワードのように見えても、実は公開してよい値のことがあります。見た目が似ているだけで秘密でないなら、漏れても問題ありません。
  2. それは、実際に悪用できるか。理屈の上で危なそうでも、実際に試すと悪用できないことがあります。本物なら、実際にそれを使って何か悪いことができるはずです。
  3. それは、外から届くか。悪用できるとしても、外から触れない内部だけの話なら、攻撃する側はそこに届きません。外から届いて、かつ悪用できて初めて、本当に危ない弱点です。

三つの観点を、確定した本物3件に当てはめた表。①本当に問題か、②実際に悪用できるか、③外から届くか。ログアウトの件は8通り中7通りで再現、監査の記録の身元の件はログインしていない相手でも可能、記録への漏れは再現済み。三つとも全部を通り、どれも「直す」と判断した。この最後の判断が、人に残る仕事。

この三つの観点を、攻撃する側のツールが挙げた誤報にも当てはめてみます。「どんなコードでもトークンが出る」は、二つ目の「実際に悪用できるか」で落ちます。悪用できたのは簡易版のサーバに対してだけで、本番のサーバに対してではないからです。誤報の多くは、この二つ目で見分けられます。「その環境で起きたこと」と「本物のサービスで起きること」を分けて考える、ということです。

三つ目の「外から届くか」は、第 2 回で書いた攻撃する側の前提と、ちょうど裏返しの関係にあります。攻撃する側は、外から届く入口を片っ端から探します。だから、守る側も「外から届くか」をいちばん重く見ます。今回の本物の 3 件は、いずれもログイン周りの、外から誰でも呼べる入口で起きます。ただ、三つ目の記録への漏れは、少し事情が違います。入口は外から呼べますが、漏れた鍵の断片が残るのはサーバの中の記録です。危なくなるのは、記録を見られる人がいるときや、記録そのものが外に漏れたときです。それでも、鍵を記録に書かないという決まりを破っているので、直すと判断しました。

本物も、無いことの証明も、両方を正しく受け取る

今回の結果を、正しくまとめます。コードを読むツールで本物が 3 件、外から試すツールで本物が 2 件(うち 1 件はログアウトの件と同じ原因)見つかり、注入や SSRF といった危険は「この範囲には無い」と証明されました。この両方を、正しく受け取ることが大事です。

本物が見つかったことは、青ざめる話ではありません。むしろ、確かめずに「たぶん大丈夫」と思っていたものを、実際に調べて「ここが弱い」と事実としてつかめた、ということです。願望が事実に変わった。これは守る側にとって前進です。そして、見つかった弱点は、どれも直し方がはっきりしています。

同時に、無いことが証明された部分は、安心してよい。今回の検査の範囲は、ログイン周りの 4 つの入口です。無いと証明されたのは、この 4 つの入口についてです。

だから、集めて仕分ける手順が要る

ここで、さっきの誤報 4 件が効いてきます。

もし、攻撃する側のツールの報告をそのまま信じていたら、深刻な入り込みが 2 件もある、と誤解したままでした。実際には、その 2 件は簡易版のサーバの甘さで、製品の弱点ではありません。逆に、外から試すツールの結果だけを見て「深刻なものは無かった」と安心していたら、監査の記録の身元の偽装や、記録への漏れを見落としたままでした。

検査の結果は、出てきたままでは信用できない。これが、今回で分かったことです。だから、種類の違う複数のツールの結果を一か所に集めて、人が一つずつ「これは本物か、誤報か」を三つの観点で見分けて、誤報を外す。この仕分けの手順が、検査そのものと同じくらい大切になります。

結果を一か所に集めて、重さの順に並べて、いつ直したかを残す。この手順は、第 9 回で、実際の画面を見ながら進めます。

自分のサービスでは何をすればいいのか

ここまでを、自分のサービスに置き換えると、やることは三つです。

一つ目。検査は、調べ方の違うツールを両方使います。外から試すものと、コードを読むもの。片方だけで「調べた」としません。どちらも、無料の正規のツールから始められます。外から試すなら ZAP、コードを読むなら次回お見せする Semgrep が、その例です。

二つ目。出てきた結果を、そのまま信じません。とくに「重大」と出たものほど、まず疑います。それは本当に自分のコードの弱点か、それとも検査のときの環境のせいか。今回のように、6 件のうち 4 件が検査の環境ややり方のせいだった、ということは、起こり得ます。ツールを選ぶときは、挙げた候補を確かめ直す手順を持っているかどうかも見てください。

三つ目。複数の結果を一か所に集めて、本物だけを残し、重さの順に並べます。外から届くもの、実際に悪用できるものを先にします。

次回

次回の第 6 回は、自分の書いたコードを検査する回です。今回の図で左上のマスにあった、コードを読む正規のツール(Semgrep)を、実際に自分のサービスのコードに実行します。入れ方、動かし方、出てきた結果の見方を、画面とともに一つずつお見せします。外から試すだけでは見えない弱点を、手元のコードから先に見つける方法です。


この連載では、攻撃ツールが誰でも無料で手に入る時代に、自分のサービスを自分で検査し、弱いところを先に見つけて直す手順を、順に示します。検査の対象は自社サービスに限り、他人のサイトを攻撃する手順は扱いません。 自分で検査するのが難しい方は、EarthLink Network が検査を代行します。弱点は見つかったが自分では直せない、という方は、私たちが修正まで引き受けます。お気軽にご相談ください。 役に立ったと感じたら、ぜひ「いいね」と記事の購読をお願いいたします。

自社プロダクトは https://www.eln.ne.jp/products にまとめています。

筆者について

上原正吉。EarthLink Network Co., Ltd. 代表。AI社員に日々の業務を任せ、開発では人が逐一指示しなくても作業が進むHOOTL(Human Out Of The Loop)の仕組みを自社で実践しています。このブログでは、業務自動化と24時間自動開発のノウハウ、具体的な設定方法、日々の運用で見つかった問題と改善を共有します。

また、AIで業務や開発を組み替えたい会社・チーム向けに、AI活用のコンサルティングも受け付けています。ご相談は www.eln.ne.jp からどうぞ。


EarthLink Network は、会社の全業務を AI で回すために、必要になったものを自社で作っています。いま作っているプロダクトの一覧と概要は、こちらにまとめています。

→ EarthLink Network が自社でつくっている18のプロダクト

会社と各プロダクトの詳細は、公式サイト www.eln.ne.jp をご覧ください。

外から攻めて検査する② ── 攻撃ツールと正規ツールで、見つかるものは違う