【Outlook VBA極限講義】添付ファイルの「隠し拡張子」を見抜き、自動化に「防御力」を実装する
こんにちは。今日もコードと向き合っているあなた、素晴らしいですね。
Outlook VBAで「添付ファイルを自動保存する」という仕組みを作れるようになったなら、あなたはすでに「マクロの記録」という殻を破り、実用的なツールを作れるエンジニアの入り口に立っています。
しかし、ここで一つ、非常に重要な話をしなければなりません。
「自動化は、ミスや攻撃も自動化してしまう」 ということです。
もし、あなたが「拡張子が `.pdf` なら保存する」という単純なロジックでコードを書いていたとしたら……。悪意のある攻撃者が送ってきた `請求書.pdf.exe` というファイルも、あなたのプログラムは「あ、PDFっぽい名前だ」と勘違いして、社内サーバーへ、あるいはあなたのPCへ、ウイルスを自動でダウンロードしてしまうかもしれません。
今回は、中級者へのステップアップとして、「ファイル名の見た目に騙されない、堅牢な拡張子判定ロジック」をマスターしましょう。ここをクリアすれば、あなたの作るツールは「ただ動くもの」から「プロが現場で使えるもの」へと進化します。
1. なぜ「Right関数」だけでは不十分なのか?
初心者の多くは、ファイル名の末尾を判定するために `Right` 関数を使います。
' ⚠️ 初心者が陥りやすい、危険なコードの例
If Right(Attachment.FileName, 4) = ".pdf" Then
' 保存処理...
End If
一見、正しく見えますよね? しかし、これには致命的な弱点があります。
「二重拡張子」の罠
攻撃者は、Windowsの設定で「登録されている拡張子は表示しない」となっていることを利用します。
例えば、`important_document.pdf.exe` というファイル。
もし、あなたが「`.pdf` が含まれていたら」という条件(`InStr` など)で判定していたら、この実行ファイル(`.exe`)をPDFとして誤認してしまいます。また、`Right(filename, 4)` で `.pdf` を探しても、`.exe` で終わっていればスルーはされますが、判定ロジックが複雑になると、こうした「末尾の取り違え」はバグの温床になります。
プロの思考: 「ファイル名の末尾が何か」を判定するのではなく、「ドット(.)から後ろの文字列が、許可されたリストに含まれているか」を、厳密に、かつ逆順から解析する必要があります。
2. 解決策:`InStrRev` を使った「真の拡張子」の抽出
ここで登場するのが、VBAの強力な武器 `InStrRev` 関数 です。
`InStr` が「文字列の先頭から」探すのに対し、`InStrRev` は 「文字列の末尾から」 検索を開始します。
ファイル名の中にドットが複数あっても、一番最後にあるドットの位置を特定できれば、それが「真の拡張子」の始まりです。
実装の設計図
1. ファイル名の中から、一番最後に出現するドット `.` の位置を探す。
2. そのドット以降の文字列を「拡張子」として切り出す。
3. その拡張子が、ホワイトリスト(許可リスト) に含まれているか照合する。
3. 実践:堅牢な添付ファイル処理コード
それでは、実際のコードを見ていきましょう。単なるコピペではなく、なぜこのように書くのか、コメントを読み解いてください。
Option Explicit
''' <summary>
''' メイン処理:受信したメールの添付ファイルを安全に保存する
''' </summary>
Sub SafeAttachmentSaver()
Dim outlookApp As Outlook.Application
Dim ns As Outlook.NameSpace
Dim folder As Outlook.MAPIFolder
Dim mail As Outlook.MailItem
Dim att As Outlook.Attachment
Dim savePath As String
' 保存先フォルダ(あらかじめ作成しておいてください)
savePath = "C:\Users\Public\Documents\SafeDownloads\"
Set outlookApp = New Outlook.Application
Set ns = outlookApp.GetNamespace("MAPI")
' 受信トレイを選択
Set folder = ns.GetDefaultFolder(olFolderInbox)
' フォルダ内のメールをループ(ここでは最新の1件を例にします)
' 実際には条件に合わせてループ処理を構築してください
For Each mail In folder.Items
If mail.Class = olMail Then
Debug.Print "Checking Mail: " & mail.Subject
' 添付ファイルのループ
For Each att In mail.Attachments
' 【重要】ここで独自の安全判定関数を呼び出す
If IsSafeExtension(att.FileName) Then
' 安全だと判断された場合のみ保存
att.SaveAsFile savePath & att.FileName
Debug.Print " [SUCCESS] Saved: " & att.FileName
Else
' 不審なファイルは警告(または無視)
Debug.Print " [WARNING] Blocked suspicious file: " & att.FileName
End If
Next att
End If
Next mail
MsgBox "処理が完了しました。", vbInformation
End Sub
''' <summary>
''' 拡張子を解析し、許可された拡張子かどうかを判定する
''' </summary>
''' <param name="fileName">ファイル名(フルパスではなくファイル名のみを想定)</param>
''' <returns>安全であればTrue、そうでなければFalse</returns>
Function IsSafeExtension(ByVal fileName As String) As Boolean
Dim dotPosition As Long
Dim ext As String
Dim allowedExtensions As Variant
Dim i As Integer
' 1. 許可する拡張子のホワイトリスト(小文字で定義するのがコツ)
' ブラックリスト(禁止リスト)方式ではなく、ホワイトリスト方式が鉄則です。
allowedExtensions = Array(".pdf", ".jpg", ".png", ".xlsx", ".docx")
' 2. 末尾からドットの位置を探す
dotPosition = InStrRev(fileName, ".")
' ドットが見つからない、またはドットがファイル名の先頭にある場合は不正とみなす
If dotPosition <= 0 Or dotPosition = Len(fileName) Then
IsSafeExtension = False
Exit Function
End If
' 3. 拡張子部分を抽出して小文字に変換(大文字 .PDF にも対応するため)
ext = LCase(Mid(fileName, dotPosition, Len(fileName) - dotPosition + 1))
' 4. ホワイトリストに含まれているかチェック
IsSafeExtension = False
For i = LBound(allowedExtensions) To UBound(allowedExtensions)
If ext = allowedExtensions(i) Then
IsSafeExtension = True
Exit For
End If
Next i
End Function
4. エンジニアの視点:ここが「プロ」の設計思想
このコードには、初級者が飛ばしがちな「設計の要諦」が3つ含まれています。
① ホワイトリスト方式の採用
「`.exe` はダメ、`.bat` もダメ……」と禁止リスト(ブラックリスト)を作ると、新しい形式のウイルスが現れた瞬間に無防備になります。
「許可したもの以外はすべて拒否する」 というホワイトリスト方式こそが、セキュリティの基本原則です。
② `LCase` による正規化
ファイル名は `REPORT.PDF` と `report.pdf` が混在することがあります。判定前に `LCase` 関数で小文字に統一(正規化)することで、比較漏れを防ぎ、ロジックをシンプルに保っています。
③ `InStrRev` と `Mid` の組み合わせ
`Right` 関数で「4文字」と決め打ちすると、`.jpeg`(5文字)や `.docx`(5文字)に対応できません。
`InStrRev` でドットの位置を特定し、そこから末尾までを `Mid` で切り出す。この手法なら、拡張子の文字数に関わらず、常に正確に「真の拡張子」を掴み取ることができます。
まとめ:一歩先の自動化へ
いかがでしたでしょうか。
「動けばいい」という段階から、「安全に、かつ確実に動く」という段階へ。
今回学んだ `InStrRev` を使った拡張子判定は、Outlook VBAだけでなく、Excel VBAやVB.NETなど、あらゆるファイル操作において一生モノの技術になります。
「オブジェクトの振る舞いを予測し、最悪のケースを想定してコードを書く」
これができれば、あなたはもう立派なエンジニアです。
さあ、自信を持って、次の自動化プロジェクトに取り掛かってください。応援していますよ!
