データ汚染と汚染防御

セキュリティ脆弱性をついて不正な操作やアクセスを行うための異常コマンドなど、危険な入力データを汚染データと呼びます。例えばSQLインジェクションでの悪意あるSQLコマンドの入力が汚染データの一種です。

そして汚染データの害を無効化する対策を汚染防御と呼びます。また汚染データがどのようにコードで広がっていくか、汚染データがシンク(汚染データが実害を発生させる脆弱性のポイント)に到達するか解析する活動を汚染解析と呼称します。

例えばかなり極端な例ですが、以下のようなコードがあるとします。

import sqlite3

input = request.args.get('command')

conn = sqlite3.connect('secure_database.db')
cursor = conn.cursor()
cursor.execute(input)

このコードは外部からの入力をそのままsecure_database.dbへのコマンドとして実行しています。ここで外部から入力される不正なSQLコマンドが汚染データであり、SQLコマンド実行部分がシンクになります。

汚染防御

汚染データが実害を発生させるのを防ぐ機構を汚染防御と呼びます。
汚染防御としては以下があります。

  • 入力バリデーション。外部からの入力データに害がないか確認し、問題があればブロックする
  • サニタイズ。有害な可能性のある文字を、安全なものに置換・除去する
  • 汚染防御済みのサポートの使用。汚染防御が実装されたAPIフレームワークを使用する。例えば前述のコードの例ならば、プリペアドステートメントを使用し、実害を及ぼさないようにする

汚染防御を困難にする脆弱性

汚染対策は前述の例ですが、こうした入力に対する汚染防御を台無しにするものがあります。例えば次のようなものです。

  • バッファオーバーフロー。別領域のメモリに汚染データを書き込めるため、汚染データが特定不能に広がる
  • 境界外読み込み(Out-of-Bounds Access)。まったく別のコードから、汚染防御を適用する前の汚染データを参照できてしまう可能性を高める

こうした脆弱性は、汚染防御で品質リスクを抑え込めなくしてしまう深刻なものですが、昔からC/C++で書かれたソフトウェアでの定番の脆弱性になっています。これはCの採用を止める、C++は最新の言語仕様のみを使う、といった手段が推される背景の一つとなっています。