「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に通知を飛ばしたりして、さらに高度な監視システムへと拡張してみてください。
その挑戦こそが、あなたを伝説のエンジニアへと押し上げるのです。
応援していますよ。
