【入門編】【中級者向け】受信メールのヘッダー情報を解析し、なりすましメールの疑いがある場合に隔離フォルダへ移動 – Outlook VBA解析バイブル

スポンサーリンク
スポンサーリンク

「From」欄を信じるな。――Outlook VBAで実装する、ヘッダー解析によるなりすましメール検知の極意

こんにちは。今日もコードの海で、最高の自動化を追求していますか?

「マクロの記録」を使って、ボタン一つでメールを移動させる。それは自動化の第一歩として素晴らしいことです。しかし、あなたがもし「真のエンジニア」を目指すのであれば、その先にある「データの真実を見抜く力」を手に入れなければなりません。

今日扱うテーマは、少しだけレベルが高い。でも、ここを乗り越えれば、あなたのOutlook VBAは「単なる便利ツール」から「堅牢なセキュリティガード」へと進化します。

テーマは、「メールヘッダーを解析し、なりすましメールを自動隔離する」。
さあ、一緒に深淵なるメタデータの世界へ踏み出しましょう。

1. なぜ「送信元アドレス」のチェックでは不十分なのか?

初心者が陥りやすい罠があります。それは、`MailItem.SenderEmailAddress` だけを見て、「このアドレスは怪しいから移動しよう」と判断してしまうことです。

実は、メールの「差出人(From)」は、誰でも簡単に偽装できてしまいます。
見た目は `ceo@yourcompany.com` となっていても、中身は全くの別人が送りつけてきている……これが「なりすましメール」の正体です。

プロのエンジニアは、見た目の顔(From)ではなく、「身分証明書(メールヘッダー)」を確認します。

注目すべきは「Authentication-Results」

現代のメール通信では、SPF、DKIM、DMARCといった認証技術が使われています。メールのヘッダーの中には、受信サーバーが「このメールは本当に正当なものか?」を判定した結果が、`Authentication-Results` という項目に刻み込まれています。

この「判定結果」を読み解くこと。これこそが、今回のミッションです。

2. アーキテクチャの設計図:効率的な監視の仕組み

ここで、設計上の重要なアドバイスを一つ。
「新しいメールが届くたびに、受信トレイの全件をループで回してチェックする」……これは絶対にやってはいけません。

メールが増えるたびに処理が重くなり、Outlookがフリーズする原因になります。

私たちが採用するのは、`Application_NewMailEx` イベントです。
これは、新しいメールが届いた「その瞬間」に、そのメールのID(EntryID)だけをピンポイントで渡してくれる、非常に軽量でスマートな仕組みです。

処理の流れ(ロジック図)

1. イベント発生: 新しいメールが届く。
2. 特定: `NewMailEx` から渡された `EntryID` を使って、対象のメールを特定。
3. 解析: メールの「インターネットヘッダー」を取得し、認証結果(SPF/DKIM等)をスキャン。
4. 判定: 認証失敗(`fail` や `softfail`)が含まれているかチェック。
5. アクション: 疑わしい場合は、即座に「隔離フォルダ」へ移動。

3. 実装:なりすまし検知エンジン

それでは、魂を込めて書いたコードを見ていきましょう。
このコードを `ThisOutlookSession` に貼り付けて使用してください。

' 【重要】このコードは ThisOutlookSession モジュールに記述してください
Option Explicit

''' <summary>
''' 新着メール受信時に自動実行されるイベントハンドラ
''' </summary>
''' <param name="EntryID">受信したメールの一意識別子</param>
Private Sub Application_NewMailEx(ByVal EntryID As String)
    Dim objItem As Object
    Dim objMail As Outlook.MailItem
    Dim strHeaders As String
    Dim strTargetFolder As String
    Dim targetFolder As Outlook.Folder
    
    On Error GoTo ErrorHandler

    ' 1. EntryIDからオブジェクトを取得
    Set objItem = Application.Session.GetItemFromID(EntryID)
    
    ' メールアイテム以外(会議出席依頼など)は無視する
    If TypeOf objItem Is MailItem Then
        Set objMail = objItem
    Else
        Exit Sub
    End If

    ' 2. 設定:隔離先のフォルダ名を指定(事前に作成しておいてください)
    strTargetFolder = "隔離フォルダ"
    
    ' 3. メールのヘッダー情報を取得
    ' InternetMessageHeaders プロパティには、認証情報を含む全てのメタデータが入っています
    strHeaders = objMail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E")
    ' ※上記プロパティタグは InternetMessageHeaders を指します
    
    ' 4. ヘッダー解析(なりすましの判定ロジック)
    ' SPFやDKIMの認証結果が "fail" または "softfail" になっていないか確認
    ' ここでは簡易的に、文字列の中に "spf=fail" や "dkim=fail" があるかを探します
    If IsSuspicious(strHeaders) Then
        ' 5. 隔離フォルダの取得と移動
        Set targetFolder = GetFolderByName(strTargetFolder)
        
        If Not targetFolder Is Nothing Then
            ' 警告ログ(イミディエイトウィンドウに出力)
            Debug.Print "[SECURITY ALERT] Suspicious mail detected: " & objMail.Subject
            
            ' メールを移動
            objMail.Move targetFolder
        Else
            Debug.Print "[ERROR] Target folder not found: " & strTargetFolder
        End If
    End If

CleanUp:
    Set objMail = Nothing
    Set objItem = Nothing
    Exit Sub

ErrorHandler:
    Debug.Print "[ERROR] Application_NewMailEx Error: " & Err.Description
    Resume CleanUp
End Sub

''' <summary>
''' ヘッダー文字列から不審な認証結果を探す関数
''' </summary>
Private Function IsSuspicious(ByVal headerText As String) As Boolean
    ' 解析のポイント:Authentication-Results ヘッダー内の判定結果を見る
    ' 実際には、より複雑な正規表現を使うのが理想的ですが、
    ' ここでは基本となるキーワードチェックを行います。
    
    Dim suspiciousKeywords As Variant
    Dim keyword As Variant
    
    ' 判定に失敗している場合によく現れるキーワード
    suspiciousKeywords = Array("spf=fail", "spf=softfail", "dkim=fail", "dmarc=fail")
    
    IsSuspicious = False
    For Each keyword In suspiciousKeywords
        ' 大文字小文字を区別せずに検索
        If InStr(1, headerText, keyword, vbTextCompare) > 0 Then
            IsSuspicious = True
            Exit Function
        End If
    Next keyword
End Function

''' <summary>
''' 指定した名前のフォルダを現在の受信トレイ配下から探すヘルパー関数
''' </summary>
Private Function GetFolderByName(ByVal folderName As String) As Outlook.Folder
    Dim Inbox As Outlook.Folder
    Dim f As Outlook.Folder
    
    Set Inbox = Application.Session.GetDefaultFolder(olFolderInbox)
    
    ' 受信トレイ直下を探す
    For Each f In Inbox.Folders
        If f.Name = folderName Then
            Set GetFolderByName = f
            Exit Function
        End If
    Next f
    
    ' 見つからない場合は Nothing を返す
    Set GetFolderByName = Nothing
End Function

4. エンジニアの視点:ここが「ハマりどころ」だ

コードを書いた後に、必ず以下の3点をチェックしてください。これを知っているかどうかが、プロとアマの境界線です。

① プロパティタグの魔法

コード内で `http://schemas.microsoft.com/mapi/proptag/0x007D001E` という呪文のような文字列を使いましたね。これは、Outlookの内部的なデータ構造(MAPI)に直接アクセスするための「住所」です。
通常の `MailItem.Subject` のようなプロパティでは取得できない、「生のヘッダー情報」にアクセスするために、このプロパティタグが必要なのです。

② 誤検知(False Positive)の恐怖

セキュリティツールにおいて最大の敵は、「正しいメールをゴミ箱に捨てること」です。
SPFやDKIMの判定が一時的に `softfail` になるケースもあります。
実運用では、いきなり `Move`(移動)させるのではなく、まずは「フラグを立てる」だけにするか、特定のドメイン(信頼できる取引先)をホワイトリスト化する処理を追加することを強く推奨します。

③ オブジェクトのライフサイクル

`NewMailEx` で受け取った `EntryID` を使って `GetItemFromID` でオブジェクトを再取得しています。これは、イベントが発生した瞬間の「スナップショット」ではなく、「今、まさにそこに存在するオブジェクト」を確実に捕まえるための、堅実な作法です。

最後に:一歩先へ進むあなたへ

お疲れ様でした。これであなたは、「メールの見た目に騙されない」という、エンジニアとして極めて重要な視点を得ました。

「マクロの記録」は、既成の道を歩むための道具です。
しかし、今回のように「ヘッダーを解析し、ロジックに基づいて判断を下す」コードを書くことは、自ら新しい道を切り拓くことに他なりません。

次は、この解析結果をログファイルに書き出したり、SlackやTeamsに通知を飛ばしたりして、さらに高度な監視システムへと拡張してみてください。

その挑戦こそが、あなたを伝説のエンジニアへと押し上げるのです。
応援していますよ。

タイトルとURLをコピーしました