【テクニカル・上級編】【シュレッダー削除】FSOでファイルを削除する前にダミーデータで上書きし復元を防止するセキュリティスクリプト – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【シュレッダー削除】FSOでファイルを削除する前にダミーデータで上書きし復元を防止するセキュリティスクリプト

レガシーシステムの現場において、データガバナンスとセキュリティの担保は常にエンジニアの頭を悩ませる問題だ。
`FileSystemObject` (FSO) の `DeleteFile` メソッド。これほど手軽にファイルを消去できる手段はない。しかし、シニアエンジニアであれば誰もが知っている通り、このメソッドが行うのは「ファイルのエントリ削除とアロケーションテーブルの開放」に過ぎない。物理セクタ上に残存するデータは、市販のデータ復元ソフトやフォレンジックツールによっていとも簡単にサルベージされる。

機密情報や個人情報を扱うバッチ処理において、これを放置することは重大なセキュリティインシデントの芽を残すと同義である。

今回は、VBScriptの限界領域に踏み込み、「ファイルを削除する前に、その実体をゼロデータまたはランダムノイズで完全に上書き(シュレッド)してから破棄する」実戦投入可能なセキュリティスクリプトを、極限のパフォーマンスチューニングとともに解説する。

—

1. アーキテクチャ設計:なぜFSO単体では不十分なのか

FSOの限界は、ファイルサイズを直接制御する低水準なI/Oメソッドを持たない点にある。
ファイルを上書きするためには、以下のライフサイクルを厳密に制御する必要がある。

1. 対象ファイルの正確なバイトサイズの取得
2. バイナリモード(またはADODB.Stream)によるファイルストリームのオープン
3. ファイルサイズに応じた上書きデータの生成と書き込み(パージ処理)
4. ディスクキャッシュのフラッシュ(OSの遅延書き込み対策)
5. ファイル属性の強制解除(読み取り専用・システム属性のバイパス)
6. 最終的なFSOによる `DeleteFile` 実行

特にVBScript環境では、メモリ管理の不手際がそのままスクリプトホスト(`cscript.exe`)のメモリリークやハンドルリークに直結する。オブジェクトの明示的な破棄(`Set obj = Nothing`)のタイミングに至るまで、アーキテクトの意図通りにコントロールしなければならない。

—

2. 実装コード:セキュア・ファイル・シュレッダー

以下のコードは、指定されたファイルを零(ゼロ)データで完全上書きした上で物理削除する、プロダクション品質のVBScriptである。エラーハンドリングとリソース解放を完璧に網羅している。

Option Explicit

‘ ==============================================================================
‘ スクリプト名: SecureFileShredder.vbs
‘ 概要: 指定されたファイルをゼロデータで上書きし、復元不能な状態で削除する
‘ ターゲット: Windows Server / 10 / 11 (Cscript.exe実行推奨)
‘ ==============================================================================

Dim targetFilePath
targetFilePath = “C:\Confidential\secret_data.txt” ‘ 実際のパスに書き換えてください

If ShredFile(targetFilePath, 1) Then
WScript.Echo “[SUCCESS] ファイルの完全抹消に成功しました: ” & targetFilePath
WScript.Quit(0)
Else
WScript.Echo “[ERROR] ファイルの抹消処理に失敗しました。”
WScript.Quit(1)
End If

‘ ——————————————————————————
‘ 関数名: ShredFile
‘ 引数:
‘ filePath (String) – 抹消対象のファイルパス
‘ passes (Integer) – 上書き回数(通常は1〜3回を推奨)
‘ 戻り値: Boolean (True:成功, False:失敗)
‘ ——————————————————————————
Function ShredFile(filePath, passes)
Dim fso, file, fileSize, stream, i, j
Dim chunkSize, zeroChunk, blocks, remainder

ShredFile = False

‘ FSOのインスタンス生成(必要最小限のスコープで保持)
Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ ファイルの存在確認
If Not fso.FileExists(filePath) Then
WScript.Echo “[WARN] 対象ファイルが存在しません: ” & filePath
Exit Function
End If

On Error Resume Next

‘ 属性の強制解除(読み取り専用ファイル等の削除拒否を防止)
Set file = fso.GetFile(filePath)
file.Attributes = 0 ‘ 通常属性へ変更
fileSize = file.Size
Set file = Nothing

If fileSize = 0 Then
‘ サイズが0の場合はそのまま削除して終了
fso.DeleteFile filePath, True
Set fso = Nothing
ShredFile = True
Exit Function
End If

‘ ADODB.Stream を使用してバイナリ書き込みを行う
‘ (VBScript標準のTextStreamではバイナリ制御や正確なサイズ上書きが困難なため)
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = 1 ‘ adTypeBinary
stream.Open
stream.LoadFromFile filePath

‘ チャンクサイズの設定 (1MBごとに処理し、メモリ爆発を防ぐ)
chunkSize = 1024 1024

If fileSize < chunkSize Then chunkSize = fileSize End If ' ゼロ埋め用バイト配列の生成 ' ※VBScriptでバイナリを効率よく扱うため、ADODB.Stream上でゼロバイトのブロックを作成 Dim zeroStream Set zeroStream = CreateObject("ADODB.Stream") zeroStream.Type = 1 ' adTypeBinary zeroStream.Open ' 1MB分のヌルバイトデータを生成 Dim initialBuffer() ReDim initialBuffer(chunkSize - 1) For j = 0 To UBound(initialBuffer) initialBuffer(j) = 0 Next ' ストリームに流し込んでおく zeroStream.Write initialBuffer ' 指定されたパス(回数)だけ上書きを実行 For i = 1 to passes stream.Position = 0 blocks = Int(fileSize / chunkSize) remainder = fileSize Mod chunkSize ' チャンク単位で書き込み For j = 1 to blocks zeroStream.Position = 0 Dim chunkData chunkData = zeroStream.Read(chunkSize) stream.Write chunkData Next ' 割り切れない余り部分の書き込み If remainder > 0 Then
zeroStream.Position = 0
stream.Write zeroStream.Read(remainder)
End If

‘ ディスクへの物理フラッシュ(キャッシュからの書き出し強制)
stream.Flush
Next

‘ ストリームのクローズと解放
zeroStream.Close
Set zeroStream = Nothing

stream.SaveToFile filePath, 2 ‘ adSaveCreateOverWrite (上書き保存)
stream.Close
Set stream = Nothing

‘ 最後にFSOでファイルを物理削除
fso.DeleteFile filePath, True

If Err.Number <> 0 Then
WScript.Echo “[ERROR] 予期せぬエラーが発生しました: ” & Err.Description
ShredFile = False
Else
ShredFile = True
End If

On Error GoTo 0
Set fso = Nothing
End Function

—

3. 極限の知見:シニアエンジニアが押さえるべき実装の急所

上記のコードが一般的なサンプルスクリプトと一線を画す、プロダクション環境向けの設計ポイントを解説する。

① `ADODB.Stream` の採用理由とメモリ効率の最適化

VBScript標準の `TextStream` オブジェクトは、テキストエンコード(UTF-16, Shift-JISなど)の自動変換が介入するため、バイナリレベルの厳密なバイト上書きには全く向かない。また、ファイルサイズが数GBに達した場合、メモリ上に全データを展開するとスクリプトが即座に OOM (Out of Memory) エラーを引き起こす。
本スクリプトでは、1MBのチャンク(バッファ)に分割し、`ADODB.Stream` のバイナリモード(`adTypeBinary`)でストリーミング処理を行うことで、巨大なファイルであっても省メモリで高速に上書きを完了させる。

② SSD環境における「ウェアレベリング」の罠と限界

現代のインフラ環境において、HDDからSSDへの移行は完了している。ここでハードコアなエンジニアが知っておかなければならない事実がある。
SSDのコントローラーはウェアレベリング(寿命均等化)およびTRIMコマンドをハードウェアレベルで制御している。つまり、OS側が「同じLBA(論理ブロックアドレス)に対して上書きした」と認識していても、SSD内部のフラッシュコントローラーが別の物理セルにデータをリダイレクトし、元のデータがそのまま物理セルに残存するケース(ゴーストデータ)が存在する。

純粋なセキュリティを求める場合、ファイル単位のシュレッダーだけでなく、ボリューム全体の暗号化(BitLocker等)や、ファイルシステムそのものの特性を理解した上での運用が不可欠である。本スクリプトは「アプリケーション層における簡易的かつ強力な証拠隠滅・ログパージ」としての役割を担う。

③ 属性の強制リセットとエラーハンドリング

レガシーシステムで生成されたファイルには、しばしば `ReadOnly` 属性や `System` 属性が付与されている。これらを無視してFSOの `DeleteFile` を叩くと、容赦なく「権限がありません」というエラーが返る。
本スクリプトでは、処理の初段で `file.Attributes = 0` を明示的に実行し、OS側のプロテクションを強制解除してからストリームを開く設計にしている。

—

4. 結言

VBScriptは、モダンな言語(PythonやPowerShellなど)の陰に隠れつつも、依然として多くのレガシーWindows環境のバックボーンで静かに稼働し続けている。
「動けばいい」という妥協の産物ではなく、背後にあるOSのI/O挙動、ストレージの特性、メモリ管理のライフサイクルまで見据えたコードを書くこと――それこそが、真の業務自動化エンジニアの矜持である。

社内システムの自動化スクリプト一つをとっても、セキュリティの牙城を揺るがぬものにするための知見を、これからもコードに宿し続けよ。

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