0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CSV数式インジェクションをExcel実機で確認:=,+,-,@の4文字と無害化

0
Posted at

はじめに

ユーザー入力をそのままCSVに出力すると、セルの先頭が = で始まる値がExcelで数式として実行される——いわゆるCSV数式インジェクション。Excelが実際にどう解釈するのかをCOM経由の実機で確認し、Python側の無害化処理とセットで整理した。

環境

  • Windows 11(ビルド 10.0.26200)
  • Python 3.11(csv モジュール。標準ライブラリ)
  • Microsoft Excel 16.0(COM経由で開いてセルの解釈を確認)

やったこと

1. 危険なCSVを書き出す

import csv

rows = [
    ["name", "memo"],
    ["通常の入力", "こんにちは"],
    ["攻撃1", "=1+1"],
    ["攻撃2", '=HYPERLINK("http://example.com","クリック")'],
    ["攻撃3", "+1+1"],
    ["攻撃4", "-1+1"],
    ["攻撃5", "@SUM(1,1)"],
]

with open("test.csv", "w", encoding="utf-8-sig", newline="") as f:
    csv.writer(f).writerows(rows)

(utf-8-sig はExcelで日本語が化けないためのBOM付き。ここではBOMが有効に働いている。)

2. Excelで開いてセルの中身を確認

PowerShell + COMで、CSVを開いた直後のセルを調べる。

$xl = New-Object -ComObject Excel.Application
$xl.Visible = $false
$wb = $xl.Workbooks.Open((Resolve-Path .\test.csv))
$ws = $wb.Worksheets(1)
2..7 | ForEach-Object {
  "B$_ : Formula=[$($ws.Cells.Item($_, 2).Formula)]  Value=[$($ws.Cells.Item($_, 2).Value2)]"
}
$wb.Close($false); $xl.Quit()

実行結果:

B2: Formula=[こんにちは]  Value=[こんにちは]
B3: Formula=[=1+1]  Value=[2]
B4: Formula=[=HYPERLINK("http://example.com","クリック")]  Value=[クリック]
B5: Formula=[=1+1]  Value=[2]
B6: Formula=[=-1+1]  Value=[0]
B7: Formula=[=SUM(1,1)]  Value=[2]

= 以外に + - @ の3文字も数式として評価された。特に +1+1 は =1+1 に正規化されて値が 2 になっている。HYPERLINKは表示が「クリック」というリンクになる。

3. 無害化して同じ確認をする

先頭が危険文字なら、'(アポストロフィ)を付けて文字列であることを明示する。

def sanitize(value: str) -> str:
    if value and value[0] in "=+-@\t\r":
        return "'" + value
    return value
with open("test_sanitized.csv", "w", encoding="utf-8-sig", newline="") as f:
    w = csv.writer(f)
    for r in rows:
        w.writerow([sanitize(c) for c in r])

Excelで開いた結果:

B3: Formula=['=1+1]  Value=['=1+1]
B4: Formula=['=HYPERLINK("http://example.com","クリック")]  Value=['=HYPERLINK("http://example.com","クリック")]
B5: Formula=['+1+1]  Value=['+1+1]
B6: Formula=['-1+1]  Value=['-1+1]
B7: Formula=['@SUM(1,1)]  Value=['@SUM(1,1)]

数式として実行されなくなった(FormulaにもValueにも計算結果が入っていない)。

ハマった点

  1. 危険なのは = だけではない。実測で + - @ も式として評価された。OWASPなどではタブ(\t)やCR(\r)を先頭に付ける手口も知られており、サニタイズは「先頭1文字の集合」で判定する。
  2. 無害化の ' はCSVインポート時に見える。Excelで手入力する場合はアポストロフィが非表示になるが、CSVインポートでは文字としてそのまま表示される(実測)。見た目を優先するなら、アプリ側の表示で1文字を外す・そもそもCSVを直接Excelで開かせない、といった判断が要る。安全性を優先して「少し汚く見える」を受け入れるのも有効。
  3. csv.writer は引用符を自動処理するが、式の評価は防げない。"=HYPERLINK(..." のようにクォートされていても、ExcelはCSVを読むときにセル文字列として解釈し直すため、数式は実行されてしまう。
  4. サニタイズは「出力の直前に1箇所」で。DBや内部データは生のまま持ち、CSVへ書き出す瞬間だけ無害化するのが事故りにくい。

まとめ

  • Excelは = だけでなく + - @ 先頭のセルも数式として評価する(実機で確認)。
  • CSV出力の直前で「先頭の危険文字に ' を付ける」サニタイズを行う。
  • 無害化後は ' が見えることを把握しておく(安全側のトレードオフ)。
  • サニタイズ関数はエクスポート処理に集約し、データ本体は汚さない。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?