PowerShellでZIPを展開する前に危険なパスと巨大展開を検査する

PowerShellカテゴリを表すパンダのイラスト PowerShell

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。.NETのZipArchive/ZipArchiveEntry公式APIを確認し、ZIPを実際に展開する前に、展開先外へ出るパスや大きすぎる展開サイズを検査するpreflight checkとして整理しています。

検証ステータス:📘 Microsoft公式仕様確認済み・実行未検証

ZIPを展開せず一覧表示するだけでも便利ですが、自動処理へ進めるならもう一段必要です。

「このZIPを指定フォルダへ展開してもよいか」を、展開前に判定すると、想定外パスや巨大な展開を止めやすくなります。

まず検査対象を開く

$zipPath = 'C:\Temp\sample.zip'
$extractRoot = 'C:\Temp\extract'

$archive = [IO.Compression.ZipFile]::OpenRead($zipPath)

ここではまだ展開しません。

1. 展開先の外へ出ないか確認する

ZIPエントリ名に .. などが含まれる場合、単純にパス結合すると意図した展開先の外を指す可能性があります。

各エントリについて「実際に展開したらどの絶対パスになるか」を計算します。

$rootFull = [IO.Path]::GetFullPath($extractRoot)
$rootPrefix = $rootFull.TrimEnd(
    [IO.Path]::DirectorySeparatorChar,
    [IO.Path]::AltDirectorySeparatorChar
) + [IO.Path]::DirectorySeparatorChar

foreach ($entry in $archive.Entries) {

    $dest = [IO.Path]::GetFullPath(
        [IO.Path]::Combine($rootFull, $entry.FullName)
    )

    if (-not $dest.StartsWith(
        $rootPrefix,
        [StringComparison]::OrdinalIgnoreCase
    )) {
        "BLOCK: $($entry.FullName)"
    }
}

目的は、文字列として .. があるかだけを見るのではなく、正規化後の絶対パスが展開ルート配下かを確認することです。

2. 展開後サイズの合計を見る

圧縮ファイル自体は小さくても、展開後に非常に大きくなることがあります。

$totalUncompressed = (
    $archive.Entries |
    Measure-Object -Property Length -Sum
).Sum

"Total uncompressed: $totalUncompressed bytes"

たとえば業務上100MBまでと決めているなら、その上限を超えた時点で自動展開を止められます。

3. ファイル数にも上限を持たせる

$count = $archive.Entries.Count

if ($count -gt 1000) {
    "BLOCK: too many entries ($count)"
}

合計サイズだけでなく、極端に多数のファイルが入っていないかも確認できます。

4. 想定拡張子だけ許可する

CSV受領処理なら、CSVとREADMEだけを許可する、といったルールも作れます。

$allowed = '.csv', '.txt'

foreach ($entry in $archive.Entries) {

    if ([string]::IsNullOrEmpty($entry.Name)) {
        continue  # ディレクトリエントリ
    }

    $ext = [IO.Path]::GetExtension($entry.Name).ToLowerInvariant()

    if ($ext -notin $allowed) {
        "REVIEW: unexpected extension $ext : $($entry.FullName)"
    }
}

preflight checkの流れ

flowchart TD
A[ZIPをOpenRead] --> B[パス正規化]
B --> C{展開先配下か}
C -- No --> X[BLOCK]
C -- Yes --> D[合計サイズ]
D --> E[ファイル数]
E --> F[拡張子/命名規則]
F --> G[人または後続処理が展開判断]

仕事でどう使えるか

  • 取引先ZIPの自動受領

  • バッチ処理前の入力検証

  • バックアップ展開

  • CI/CD成果物の検査

  • ユーザーアップロードZIPの事前確認

では、「ZIPだから展開する」ではなく、展開条件を先にルール化できます。

注意点

この例だけで悪意あるZIPを完全判定できるわけではありません。

実運用ではさらに、

  • 暗号化ZIPの扱い

  • シンボリックリンク等の特殊エントリ

  • 個々のファイルサイズ上限

  • 圧縮率

  • ファイル名の長さ

  • マルウェア検査

  • 展開先の権限

なども用途に応じて確認します。

Disposeを必ず行う

$archive.Dispose()

実際のコードでは try/finally を使い、途中で検査エラーになっても閉じる形が安全です。

まとめ

  • ZIPは展開前に危険なパスを検査できる

  • 文字列の .. 検査だけでなく絶対パス正規化で判定する

  • 展開後合計サイズとファイル数に上限を持てる

  • 許可拡張子を決めると受領処理を安全側へ寄せられる

  • preflight check後に初めて展開判断をする

公式情報・一次情報

文書情報

記事タイトル
PowerShellでZIPを展開する前に危険なパスと巨大展開を検査する
作成日
更新日
Source URL
https://papanda925.com/?p=15394

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

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