生成系 AI でフィッシングサイト判定をしてみた①

:::note warn
以下ご理解いただける方のみお読みください。

- 私（iron）が記載している投稿は **一個人の見解** であり、特定の企業や団体の見解や主張ではありません。一つの情報としてご覧ください。
- この記事は **同業の方への共有を目的として記載** しています。
:::

# 生成系 AI でフィッシングサイト判定をしてみた①

## TL;DR

- 最近、生成系 AI を活用してフィッシングサイトかどうかを判定するお話が活発になってきたので、自分でも試してみた。
- まずは ChatGPT の GPT Builder でさくっと作ってみた。厳密な検証はできていないが、情報ソースで言われているとおり、それなりに動く模様。
- しかし ChatGPT で量をさばくにはとても非効率なので OpenAI の API を活用して量をこなせるようにしたり、トークン上限に当たらないように工夫したりする必要がありそう。

## 経緯

近年、フィッシング詐欺被害が広がっていることを踏まえ、警察庁は生成系 AI を使ってフィッシングサイトを判別・判定するシステムの導入を目指す方針を決めた模様。

https://news.yahoo.co.jp/articles/a0260c4c3b838b24396e3f2997a1524ef8a6ee7c

上述のニュース記事にも書かれているとおり、NTT セキュリティ・ジャパンさんがシステムを作っている様子。生成系 AI を活用するにあたって考え方のもとになったのが 2023/06 に同社が [「Detecting Phishing Sites Using ChatGPT」と題して発表した論文](https://arxiv.org/abs/2306.05816) と推測される。

https://arxiv.org/abs/2306.05816

この論文では生成系 AI を活用してフィッシングサイトを判定する検証が書かれており、GPT-4V を利用して試したところ、Precision が 98.7%、Recall が 99.6% とそれなりの精度・再現率で判定できているとのこと（以下 Abstract を引用）。

> The experimental results using GPT-4V demonstrated outstanding performance, with a precision of 98.7% and a recall of 99.6%, outperforming the detection results of other LLMs and existing systems. 

:::note 
「Precision や Recall って何ですか？」という方はこちらの記事が参考になるかと。機械学習の評価指標としてよく用いられる値。

> **Accuracy/Recall/Precisionってややこしくない?? 機械学習 - Qiita**
https://qiita.com/K5K/items/5da52e99861483cae876
:::

なお、「論文ではなくもう少し概要で読みたい」「日本語でざっくり読みたい」方々は同社が解説記事を出しているのでこちらを参考にしていただければ。

https://jp.security.ntt/tech_blog/102ih4e

## とりあえず作ってみる

ChatGPT Plus を契約していると GPT Builder が使えるので今回はそれを活用していく。

ChatGPT にログインしたあと、左側のサイドバーから **[GPT を探索する]** をクリックし、右上にある **[+ GPT を作成する]** をクリックする。

![GPT 作成画面まで](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188227/e9aafe94-e96f-2fab-857d-8b6c11796da8.png)

そうすると以下のページのとおり GPT の作成画面（GPT Builder 画面）に移動する。ここから GPT へのプロンプトなどを設定していく。

![GPT 作成画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188227/8e1fc98d-b550-3ae3-37b4-c35939a43fd9.png)

### Name と Description

ここはお好みで設定。

### Instructions

ChatGPT へのプロンプトを書いていく。

前述の NTT セキュリティ・ジャパンさんの論文や解説ページでプロンプトが書かれているので参考にしつつ、 ChatGPT などのプロンプトエンジニアリングの基本として必要な「立場を指定する」「作業方法を指定する」「具体的に書く」「出力を指定する」ことを前提に書いていく。

書いたことの概要としては以下のとおり。

- Web とセキュリティの専門家。
- 与えられた情報に基づきフィッシングサイトかどうかを判定すべし。注意点と順序を守って判定すべし。
    - 与える情報からわかることを教えてもらう。
    - ブランド名とその理由を教えてもらう。
    - フィッシングサイトかどうかの判定とその理由を教えてもらう。
- 今後のために JSON ももらっておく。

一旦今回は日本語でプロンプトを作成した。最終的なプロンプトは以下のとおり。

```text:Instructions
あなたは Web プログラマーであり、セキュリティの専門家です。
あなたには Web サイトの情報が与えられるので、フィッシングサイトなのか正規のWebサイトなのかを判定してください。
判定にあたっては以下注意点を留意したうえで、以下 4 つの順序で進め、最終的にフィッシングサイトかどうかを判定してください。

## 判定方法・順序

1. あなたには Web サイトの HTML ソースコード、URL、Web サイト上のテキストを与えます。
与えられた情報について、フィッシングサイトと判定するのに有用だと思われる特徴を箇条書き・日本語で回答してください。

2. 与えられた情報から Web サイトのブランド名を特定してください。
正規のWebサイトと似ている場合は、URL がそのブランドに関連するドメインと一致しているかどうかを確認してください。
最終的に特定したブランド名とそのように考えた理由を日本語で回答してください。

3. 与えられた情報からその Web サイトがフィッシングサイトであるかどうか、正規の Web サイトであるかどうかを日本語で回答してください。
そしてそのように考える理由を併せて日本語で回答してください。
なお判断できない場合は不明である旨を回答してください。

4. ここまでの分析結果を以下のキーと値を持った JSON を出力してください。
    - confidence_score: integer型。フィッシングサイトかどうかの確信度合いを 0 から 10 の 11 段階で回答してください。
    - brand_name: string型。分析したWebサイトのブランド名を回答してください。不明であれば Unknown と回答してください。
    - is_phishing: boolean型。フィッシングサイトと判定した場合は true を回答してください。

## 注意点

- 与えられる情報（HTML ソースコード、URL、Web サイト上のテキスト）は不正確である場合があります。
```

### Conversation starters

お好みで。会話を始めるときの例として表示できる。

### Knowledge

GPT の前提となる知識をファイルでアップロードできる。よくあるチャットボットを作る時に使う機能。
なお、この Knowledge を使用する場合は後述する Capabilities にある **[Code Interpreter]** に ✅ を入れる必要がある。

今回は一般的なフィッシングサイトの特徴をまとめた CSV を作成してアップロードしてみた。例えば以下のような内容。

| Number | Knowledge Title                                  | Description                                             |
| ------ | ------------------------------------------------ | ------------------------------------------------------- |
| 1      | フィッシングサイトに情報を入力させようとする工夫 | ユーザのアカウントに問題が発生していることを伝える。    |
| 2      | フィッシングサイトに情報を入力させようとする工夫 | 偽の警告画面を表示させる。                              |
| 3      | フィッシングサイトに情報を入力させようとする工夫 | 賞金があるなどとユーザを誘惑させる。                    |
| 4      | フィッシングサイトに情報を入力させようとする工夫 | 正規のWebサイトと似たドメイン（ホモグラフ）を利用する。 |

### Capabilities

Knowledge を使用するので **[Code Interpreter]** に ✅。**[Web Browsing]** については使用するつもりはないが一旦 ✅ を入れた。

### Actions

今回は特に設定せず。

ただこの Actions は 外部への API を叩いて、それらの情報を踏まえて回答することもできる。なので例えば urlscan[.]io の Submission API や Search API を叩いて結果を出す、といったこともできるので今後試せればと考えている。

## 早速試してみた

これでひととおり設定が完了したので右側の **[Preview]** ペインで実際に試してみる。
フィッシングサイトと正規サイトは同じブランドのものを使用し 1 回ずつチャットは廃棄、プロンプトについては以下の形式で入力することにした。

:::note warn
以下の例では ` が Markdown で解釈されてしまうので空白を入れているので留意していただきたい。
:::

```
URL: {URL}

HTML:
` ` `
{ここに HTML ソースコード}
` ` `

TEXT:
` ` `
{ここにプレーンテキスト}
` ` `
```

### フィッシングサイト

#### :bank: 某銀行

:ok: 正しくブランドを判定したうえでフィッシングサイトと判定しました。

<details><summary>GPT の回答</summary>

> **このサイトの特徴**
>
> - **エンコーディング**: 文書の文字コードがShift_JISであること。現代のウェブサイトではUTF-8が一般的ですが、日本のサイトではまれにShift_JISを使用する場合もあります。しかし、金融機関などの公式サイトではセキュリティや互換性の観点からUTF-8が推奨されます。
> - **リンクの使用**: ページ内のリンクが多く`#`で始まるものがあり、実際のページへのリンクではなくプレースホルダーとして使われている可能性があります。これはユーザーを欺くための一般的な手法です。
> - **スタイルシートとスクリプトの参照**: 外部スタイルシートやスクリプトへのリンクが、標準的な命名規則に従っていないか、または奇妙なパスを持っている場合があります。これはサイトの正当性を疑問視させます。
>
> **ブランド名の特定**
>
> このWebサイトは「●●●●銀行」を名乗っています。
>
> **判定と理由**
>
> このWebサイトは**フィッシングサイトである可能性が高い**と判定します。理由は以下の通りです。
>
> - **URLの複雑さと非一般性**: 正規の銀行サイトでは、顧客が識別しやすいシンプルなURLを使用することが一般的です。このサイトのURLは非常に複雑で、フィッシングサイトによく見られる特徴です。
> - **デザインと表記の正確さ**: 「●●●●銀行」という名前を使用しており、正規の企業を装っているようですが、URLやその他の要素が正規のものであるかどうかは、直接確認する必要があります。
> - **技術的な実装**: ページの技術的な実装に疑問点があります。例えば、JavaScriptを無効にした際の警告や、セキュリティ対策としての`<noscript>`タグの使用など、フィッシングサイトではなく正規のサイトで期待される機能ですが、これだけで安全であるとは限りません。
>
> **分析結果（JSON形式）**
>
> ```json
> {
>   "confidence_score": 8,
>   "brand_name": "●●●●銀行",
>   "is_phishing": true
> }
> ```
</details>

#### :electric_plug: 某インフラ①

:ok: 正しくブランドを判定したうえでフィッシングサイトと判定しました。

<details><summary>GPT の回答</summary>

> **特徴**
>
> - **ドメイン名**: `●●●●.cn` このドメイン名は、●●●●とは無関係である可能性が高いです。通常、大手企業や公共機関は、そのブランド名に関連したドメイン名を使用します。
> - **メタタグのreferrerポリシー**: `<meta name="referrer" content="never">` この設定は、リファラー情報を一切送信しないようにするもので、ユーザーを追跡することなく、特定のアクションを促すフィッシングサイトで見られる特徴です。
> - **テキスト入力の指示**: ユーザーに電話番号を入力させることで、個人情報を収集しようとする意図があります。正規の●●●●のウェブサイトでは、請求書の確認に電話番号の入力を必須とすることは一般的ではありません。
> - **スタイルシートとスクリプトファイルのパス**: スタイルシートやスクリプトのファイルパスが`./dianfei/1/`になっており、これは一般的な命名規則に従っていない可能性があります。また、これらのファイルが存在するディレクトリ名が意味不明で、正規の企業サイトとしては不自然です。
>
> **ブランド名の特定**
>
> このWebサイトは「●●●●」を名乗っています。
>
> **判定と理由**
>
> このWebサイトは**フィッシングサイトである可能性が高い**と判定します。理由は以下の通りです。
>
> - ドメイン名が「●●●●」と関連がなく、正規の企業が使用するドメイン名とは異なるため。
> - ユーザーから個人情報を収集しようとする内容が含まれており、これは典型的なフィッシングの手口です。
> - 正規の企業や機関のウェブサイトで使用される技術的、デザイン的要素と一致しない点が多く見られます。
>
> **分析結果（JSON形式）**
>
> ```json
> {
>   "confidence_score": 9,
>   "brand_name": "●●●●",
>   "is_phishing": true
> }
> ```
</details>

#### :telephone: 某インフラ②

:ok: 正しくブランドを判定したうえでフィッシングサイトと判定しました。

<details><summary>GPT の回答</summary>

> **特徴**
>
> - **ドメイン名の関連性**: `●●●●.com`は、●●●●と直接関連があるようには見えない、一般的でないドメインです。これはフィッシングサイトの一般的な特徴であり、信頼されているブランドを装うために用いられます。
> - **JavaScriptの使用**: ユーザーがJavaScriptを有効にしていない場合に表示される内容とJavaScriptを使用して動的にコンテンツを生成する方法が使用されています。これ自体が必ずしも怪しいわけではありませんが、フィッシングサイトでは、検出を避けるためにこのようなテクニックが用いられることがあります。
> - **外部リソースへのリンク**: スタイルシートやJavaScriptファイルなど、多くの外部リソースへのリンクが含まれていますが、これらのリソースが安全である保証はありません。
> - **セキュリティ機能の欠如**: フォームにセキュリティや検証機能が不足しているか、見えないことがあります。例えば、二要素認証やCAPTCHAが見当たりません。
>
> **ブランド名の特定**
>
> このWebサイトは「●●●●」を名乗っています。
>
> **判定と理由**
>
> このWebサイトは**フィッシングサイトである可能性が高い**と判定します。理由は以下の通りです。
>
> - **ブランドとの不一致**: 与えられたURLと実際に表示されているコンテンツ（●●●●）は、正規のブランドのWebサイトで使用されるものと一致しません。特にドメイン名が正規の●●●●のドメインとは異なります。
> - **ユーザー誘導の仕方**: ユーザーに個人情報（例：●●●●、パスワード）を入力させる方法が、フィッシングサイトによく見られるパターンに沿っています。また、セキュリティ関連の情報が不十分であることも疑問を呈します。
>
> **分析結果（JSON形式）**
>
> ```json
> {
>   "confidence_score": 8,
>   "brand_name": "●●●●",
>   "is_phishing": true
> }
> ```
</details>

### 正規サイト

#### :bank: 某銀行

:triangular_flag_on_post: 一旦正解だが判定結果が怪しい。
正しくブランドを判定しフィッシングサイトではないと結論を出したが、確定的な判断ができない（i.e., `confidence_score` が低い）とのこと。

<details><summary>GPT の回答</summary>

> **フィッシングサイトの特徴**
>
> 1. **URLが正規のドメインと異なる**: URLは `https://●●●●` となっており、`●●●●.co.jp`のドメインを使用しています。このドメインは正規のものに見えますが、サブドメインやパスに疑わしい文字列が含まれているかもしれません。
> 2. **HTMLのメタデータやリンクが怪しい**: `charset`が`shift_jis`に設定されており、これ自体がフィッシングサイトであることを示す証拠ではありませんが、日本のウェブサイトで一般的です。また、JavaScriptファイルやCSSファイルへの外部リンクがありますが、これらがフィッシング目的で悪意のあるコードを含んでいる可能性があります。
> 3. **ユーザー認証情報を要求する**: ログイン情報（店番号、口座番号、パスワード）を求めるフォームがあります。これは正規の銀行サイトでも見られる機能ですが、フィッシングサイトでも同様の手口が用いられます。
> 4. **セキュリティ関連の警告がない**: HTML内において、セキュリティに関する明確な警告や説明が見当たらないことも疑問点です。ただし、これだけではフィッシングサイトであると断定するには不十分です。
> 5. **スクリプトやリダイレクトの使用**: サイトがユーザーの情報を盗み取る目的でスクリプトを使用している可能性があります。特に、ユーザーのセッション情報を外部サーバーに送信するようなスクリプトが含まれているかもしれません。
>
> **ブランド名の特定**
>
> ブランド名は「●●●●」と特定されます。これはHTMLのタイトルや本文から明らかです。また、ドメイン名にも「●●●●.co.jp」とあり、これが正規のブランドに関連する可能性が高いことを示しています。
>
> **フィッシングサイトかどうかの判断**
>
> 上記の情報だけでは、このウェブサイトがフィッシングサイトであるか正規のウェブサイトであるかを確実に判断することは難しいです。ドメインが正規のものであること、HTMLの構造が複雑で実際の銀行サイトと似ていることなど、いくつかの要素は正規のサイトであることを示唆しています。しかし、最終的な判断を下す前にさらなる検証が必要です。例えば、ドメインの登録情報の確認、サイトのSSL証明書の検証、実際の●●●●のカスタマーサポートに確認を取るなどの手段が考えられます。
>
> **分析結果のJSON形式での出力**
>
> ```json
> {
>   "confidence_score": 5,
>   "brand_name": "●●●●",
>   "is_phishing": false
> }
> ```
>
> この分析では、完全な確信には至っていませんので、`confidence_score`を中間の値`5`としています。ブランド名は「●●●●」と特定しましたが、このサイトがフィッシングサイトであるかどうかは判定できていないため、`is_phishing`は`false`としています。ただし、この判断はあくまでも利用可能な情報に基づくものであり、最終的な確認は必要です。
</details>

#### :electric_plug: 某インフラ①

:ok: 正しくブランドを判定したうえで正規サイトと判定しました。

<details><summary>GPT の回答</summary>

> **特徴点の分析**
>
> 1. **URLの構造**:  このURLは、●●●●の公式ドメインである `●●●●.co.jp` を含んでいます。サブドメインが `●●●●` であり、これは「エンドポイント認証」を意味する可能性があります。これは一見合理的に見えます。
> 2. **HTMLメタデータとリンク**: メタタグやリンク先が安全で一般的に信頼されるソース（例: `cdn.auth0.com` など）からのものであること。`robots` タグが `noindex, nofollow` に設定されていることは、ログインページが検索エンジンにインデックスされないように設定されている正常な振る舞いを示しています。
> 3. **テキストとロゴ**: ページ上のテキストとロゴからは、「●●●●」というブランド名が確認できます。これは●●●●の一般向けサービスを連想させます。
> 4. **セキュリティ特性**: HTML内でGoogle Tag ManagerやReCaptchaなどのセキュリティ関連のスクリプトが使用されており、これらは一般的に合法的なウェブサイトで見られる特徴です。
> 5. **ユーザーインターフェース**: ユーザーインターフェイスに関するカスタムスクリプトがあり、特にアクセシビリティやユーザビリティの向上を図っていることが伺えます。これは、ユーザーに良い体験を提供しようとする正規のウェブサイトの特徴です。
>
> **ブランド名の特定**
>
> 与えられた情報から、このウェブサイトは「●●●●」というブランド名に関連しています。URLが `●●●●.co.jp` ドメイン下にあることから、このブランドは●●●●に関連していると特定できます。
>
> **フィッシングサイトか正規のWebサイトか**
>
> 上記の分析に基づき、このウェブサイトは**正規のWebサイト**であると考えられます。理由は以下の通りです。
>
> - **ドメインの信頼性**: `●●●●.co.jp` は●●●●の公式ドメインであり、サブドメインとパスも合理的に見えます。
> - **セキュリティ対策の存在**: Google Tag ManagerやReCaptchaなどのセキュリティ対策が実装されています。
> - **ブランド名の一貫性**: ブランド名がウェブサイト全体で一貫して使用されており、特にロゴやテキストで明確に表示されています。
>
> **分析結果のJSON出力**
>
> ```json
> {
>   "confidence_score": 9,
>   "brand_name": "●●●●",
>   "is_phishing": false
> }
> ```
</details>

#### :telephone: 某インフラ②

:ok: 正しくブランドを判定したうえで正規サイトと判定しました。

<details><summary>GPT の回答</summary>

> このWebサイトに関する分析を行う前に、まずは与えられた情報に基づいてフィッシングサイトと判定するための特徴を挙げます。
>
> 1. **URLの構造とドメイン**: ドメイン名が有名なブランドやサービスと似ているが、細部に違いがあるか、または意図的に誤解を招くような追加の文字列やサブドメインが含まれていないか。
> 2. **SSL/TLS証明書**: サイトがセキュアな接続を使用しているか（HTTPS）と、証明書が有効であるか。
> 3. **コンテンツとデザイン**: 公式サイトからコピーされたコンテンツや、公式に似て非なるデザインの使用。
> 4. **ログインフォームの処理方法**: ユーザー入力情報が第三者に送信されるか、または不審なスクリプトが組み込まれているか。
> 5. **外部リンクとリソース**: 外部の不審なドメインにリンクしているか、またはそこからスクリプトやスタイルシートを読み込んでいないか。
> 6. **スクリプトと追跡**: ユーザーの行動を追跡するためのスクリプトや、不審な動作をするスクリプトの組み込み。
> 7. **ブランド名やロゴ**: 公式のブランド名やロゴを無許可で使用しているか、若干の変更を加えているか。
>
> **ブランド名の特定**
>
> 与えられたHTMLソースコード、URL、およびテキストの内容から、このWebサイトが「●●●●」のブランド名を使用していることが明らかです。サイト上で「●●●●ログイン」や「●●●●」という用語が使われており、●●●●の著作権表記も存在します。
>
> **フィッシングサイトか正規のWebサイトかの判定**
>
> - **URLの検討**: 提供されたURLは `https://●●●●` であり、これは●●●●の正規のドメイン名 `●●●●.jp` を含んでいます。サブドメインとディレクトリ構造が複雑であり、一見して正規またはフィッシングサイトと断定するのは難しい部分があります。
> - **HTMLとテキスト内容**: HTMLの構造やテキスト内容は、●●●●の公式サービスに関連するものであることを示唆しています。特に●●●●の著作権表記や、●●●●を使用することの言及は、このサイトが正規の可能性を高めます。
> - **セキュリティ特徴**: ソースコード中には、ユーザーのセキュリティを確保するためのJavaScriptのスクリプトが含まれており、セキュアな接続（HTTPS）を使用しています。また、フィッシングサイトにありがちな明らかなセキュリティ上の欠陥や不審な点は見受けられません。
>
> **結論**
>
> 与えられた情報から、このWebサイトは「●●●●」の正規のWebサイトであると判断します。URLが正規のドメイン構造を持ち、HTMLソースコードやサイト上のテキストが正規のサービスと一致しているためです。ただし、完全な確信を持つためには、さらに詳細な調査（例えば、ドメインの登録情報の確認や、●●●●からの公式な確認）が必要です。
>
> **分析結果のJSON出力**
>
> ```json
> {
>   "confidence_score": 8,
>   "brand_name": "●●●●",
>   "is_phishing": false
> }
> ```
</details>


## 結果と判明している課題

3 つの正規サイトと 3 つのフィッシングサイトで試した結果、1 つ怪しいものがあったが一旦すべて正解だった。
きちんと利用していくにはさらに厳密な検証やらプロンプトエンジニアリングが必要だが、取り急ぎそれっぽいものを作ることができた。

取り急ぎすぐにわかる課題は以下の 3 点。

1. **[回答揺れへの対応](#回答揺れへの対応)：**
指定していないことを回答してくるパターンをどうするか？
1. **[量への対応](#量への対応)：**
判定するフィッシングサイトが大量になってきたとき、どうするか？
1. **[トークン上限への対応](#トークンの上限)：**
HTML ソースなどを送信する都合、トークン上限の壁にあたってしまう

### 回答揺れへの対応

今回は考え方の経過を出力させているため回答揺れがそれなりに見えるが、最終的には JSON のみを出力するなどして出力方法を厳密に指定すればある程度解消できると思われる。

### 量への対応

ChatGPT は対話型で実施できる一方で自動化の壁があるので、本格的に量をこなすようになった場合は OpenAI の API などを活用していく必要がある。

### トークンの上限

OpenAI のモデルに応じてトークンの上限が存在するため、このあたりの実装も考慮が必要。
例えばあまりにも長い HTML コードやコンテンツになってくるとプロンプトがトークン上限を超えてしまって利用できなくなってしまう。

OpenAI のトークン化には Python ライブラリの `Tiktoken` が利用されているよう（以下引用）なので、実装する場合はこのあたりを活用してトークン上限ぎりぎりまで使えるように制御する必要がありそう。

> Alternatively, if you'd like to tokenize text programmatically, use Tiktoken as a fast BPE tokenizer specifically used for OpenAI models.

https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them

https://github.com/openai/tiktoken