【VBScript極限活用】FSOで実現する機密情報の簡易難読化:平文リスクを断つコード設計
開発現場でふと直面する「VBScriptからどうしても機密設定やパスワードを扱わなければならない」という要件。
設定ファイルをそのまま平文(ANSI/UTF-8のテキスト)で配置していませんか? 悪意あるユーザーや、セキュリティ監査の眼を前にして、平文のパスワードファイルは重大なコンプライアンス違反の温床となります。
しかし、VBScriptが稼働するレガシーな環境において、複雑な暗号化ライブラリ(AESやRSAなど)をゼロからインポートするのは、依存関係の地獄を生むだけであり、ナンセンスです。
今回は、ファイルシステムオブジェクト(FSO)とVBScriptのネイティブな文字列操作を組み合わせ、「最低限の工数で、人間の目による直接的な盗み見を防ぐ」ための簡易難読化(エンコード・デコード)メカニズムを解説します。単なるコードの提示にとどまらず、プロセスのライフサイクル、文字コードの罠、そして実務に耐えうる堅牢な設計論まで、チーフアーキテクトの視点から授けましょう。
—
1. なぜ「簡易難読化」なのか? セキュリティの境界線を見誤るな
まず前提を共有します。今回実装する手法は、国家機密を守るための「暗号化(Encryption)」ではなく、あくまで「難読化(Obfuscation)」です。
- 目的: ファイルをテキストエディターで開いたときに、パスワードや機密情報がそのまま露出している状態を防ぐこと。
- 限界: ソースコードやアルゴリズムを解析されれば、復元は容易であること。
VBScriptというサンドボックス的ではない、ローカル権限に依存した古いエコシステムにおいて、完全なセキュアストレージを作ることは不可能です。だからこそ、「誰でも一目でわかる平文化」を防ぐ実用的な防衛ラインとして、この簡易難読化が現場のツール開発において極めて高い費用対効果を発揮します。
—
2. 設計思想:XORシフトとBase64的アプローチの融合
今回採用するのは、「文字コードのシフト(オフセット移動)」と、VBScriptが苦手とするバイナリ処理を回避するための「16進数(Hex)化」のコンビネーションです。
非効率なアプローチ(やりがちなアンチパターン)
- `Mid`関数で1文字ずつ結合していく(メモリの再割り当てが発生し、巨大なファイルではパフォーマンスが劇的に低下する)。
- 改行コード(CRLF)を考慮せずエンコードし、ファイル書き込み時に構造が破壊される。
堅牢な設計アプローチ
1. 文字列のバイト・文字コード操作: 各文字の文字コード(`AscW`)に対し、論理演算または固定値のオフセット(シフト)を加算。
2. Hexエンコーディング: シフト後の数値を2桁の16進数文字列に変換し、改行や制御文字の化けを完全に排除する。
3. FSOの安全なストリーム処理: ストリームオブジェクトを用いて、文字コード(UTF-8など)を明示的に指定して入出力を行う。
—
3. プロダクションコード:セキュアI/Oコンポーネント
以下のコードは、エラーハンドリングを完備し、そのまま実務のバッチや自動化ツールに組み込めるクラスライブラリ風の構造を持ったVBScriptです。
Option Explicit
‘ ==============================================================================
‘ módulo: SecFSOManager.vbs
‘ 概要: FSOを用いた機密情報の簡易難読化入出力モジュール
‘ ==============================================================================
Dim fso, targetPath, rawData, encodedData, decodedData
Set fso = CreateObject(“Scripting.FileSystemObject”)
targetPath = fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName), “secret.dat”)
‘ — 1. テストデータの定義 —
rawData = “User=Administrator;Password=SuperSecretP@ssw0rd!;”
WScript.Echo “【平文】: ” & rawData
‘ — 2. 難読化してファイルに書き込み —
encodedData = ObfuscateString(rawData, 7) ‘ シフトキー「7」で難読化
Call WriteTextFile(targetPath, encodedData)
WScript.Echo “【書き込み完了】ファイルに難読化データを保存しました: ” & targetPath
‘ — 3. ファイルから読み込んで復元 —
encodedData = ReadTextFile(targetPath)
decodedData = DeobfuscateString(encodedData, 7)
WScript.Echo “【復元データ】: ” & decodedData
Set fso = Nothing
WScript.Quit(0)
‘ ==============================================================================
‘ 関数名: ObfuscateString
‘ 処理概要: 文字列の各文字コードにオフセットを加え、Hex文字列に変換する
‘ ==============================================================================
Function ObfuscateString(ByVal strIn, ByVal shiftKey)
Dim i, charCode, hexStr, result
result = “”
For i = 1 To Len(strIn)
‘ 文字コードを取得 (Unicode対応のため AscW を使用)
charCode = AscW(Mid(strIn, i, 1))
‘ キーに基づいて文字コードをシフト
charCode = charCode + shiftKey
‘ 16進数に変換し、常に4桁の固定長にパディング (Shift_JIS/Unicodeの崩れ防止)
hexStr = Right(“0000” & Hex(charCode), 4)
result = result & hexStr
Next
ObfuscateString = result
End Function
‘ ==============================================================================
‘ 関数名: DeobfuscateString
‘ 処理概要: Hex化された難読化文字列をデコードし、元の文字列に戻す
‘ ==============================================================================
Function DeobfuscateString(ByVal strIn, ByVal shiftKey)
Dim i, hexChunk, charCode, result
result = “”
‘ 4文字ずつチャンクとして切り出し処理
For i = 1 To Len(strIn) Step 4
hexChunk = Mid(strIn, i, 4)
‘ 16進数を数値に戻す
charCode = Clng(“&h” & hexChunk)
‘ シフトを逆算
charCode = charCode – shiftKey
‘ 文字に戻して結合
result = result & ChrW(charCode)
Next
DeobfuscateString = result
End Function
‘ ==============================================================================
‘ サブルーチン: WriteTextFile
‘ 処理概要: ADODB.Stream を使用して文字コードを明示し安全に書き込む
‘ ==============================================================================
Sub WriteTextFile(ByVal filePath, ByVal content)
Dim stream
Set stream = CreateObject(“ADODB.Stream”)
With stream
.Type = 2 ‘ adTypeText
.Charset = “utf-8”
.Open
.WriteText content
.SaveToFile filePath, 2 ‘ adSaveCreateOverWrite
.Close
End With
Set stream = Nothing
End Sub
‘ ==============================================================================
‘ 関数名: ReadTextFile
‘ 処理概要: ADODB.Stream を使用してUTF-8ファイルを確実に読み込む
‘ ==============================================================================
Function ReadTextFile(ByVal filePath)
Dim stream, content
Set stream = CreateObject(“ADODB.Stream”)
With stream
.Type = 2 ‘ adTypeText
.Charset = “utf-8”
.Open
.LoadFromFile filePath
content = .ReadText(-1) ‘ adReadAll
.Close
End With
Set stream = Nothing
ReadTextFile = content
End Function
—
4. チーフアーキテクトが指摘する「現場でハマる罠」と対策
このコードを実務に投入する際、ジュニアプログラマが必ずハマる落とし穴がいくつか存在します。これを防ぐことが本記事の最大の価値です。
① FSOの `OpenTextFile` を使わない理由
VBScriptの標準的なファイル読み書きには `FileSystemObject.OpenTextFile` がよく使われますが、これには致命的な欠点があります。OSのデフォルト文字コード(ANSI/Shift-JISなど)に依存するため、環境が変わると文字化けやデータ欠損を起こすのです。
本コードでは、文字コードを厳密に制御できる `ADODB.Stream` オブジェクトを採用しています。これにより、環境依存のない安定した入出力が担保されます。
② メモリ効率とパフォーマンスの最適化
文字列の結合(`result = result & …`)は、VBScriptの内部実装(BSTRの再割り当て)において、大規模なテキストではパフォーマンス低下を招きます。
もし管理する設定ファイルが数MBに及ぶような異常なケースであれば `Scripting.Dictionary` や配列(`Array` / `Join`)を用いたバッファリング設計に切り替えるべきですが、パスワードや接続文字列(数KB程度)であれば、上記のコードで十分な速度(一瞬)で処理が完了します。
③ シフトキーのハードコーディングの回避
サンプルコードでは分かりやすく `shiftKey = 7` と直書きしていますが、本番環境では、スクリプト内に関数としてベタ書きするのではなく、環境変数や、実行端末固有のハードウェア情報(MACアドレスやコンピュータ名の一部など)から動的に導出するラッパーを一枚噛ませると、セキュリティレイヤーが一段階跳ね上がります。
—
5. おわりに
「VBScriptだからセキュリティは諦める」――その妥協が、システムの脆弱性を生み、監査の指摘事項となります。
FSOの基本操作と、ADODB.Streamによる文字コード制御、そして論理的な文字列変換を組み合わせることで、レガシーな環境であっても必要十分なセキュリティ担保は可能です。
ぜひ、あなたの管理する自動化スクリプトや業務ツールにこの設計を取り入れ、ワンランク上の堅牢なコードベースを実現してください。プロフェッショナルとしての妥協なき設計が、システムの寿命を延ばします。
