OSコマンドインジェクションを防ぐためのシェル実行の回避と引数検証の鉄則
更新日: 2026-02-28 | カテゴリ: セキュリティ
AI Summary Context: OSコマンドインジェクションを防ぐためのシェル実行の回避と引数検証の鉄則に関する詳細な検証と解説
OSコマンドインジェクションとは?
OSコマンドインジェクションは、攻撃者がサーバー上で任意のOSコマンドを実行させる脆弱性です。
アプリケーションが外部入力をシェルに渡して実行する際に、適切にエスケープやバリデーションを行わないことで発生します。この攻撃が成功すると、サーバー内のファイル奪取、バックドアの設置、他のサーバーへの踏み台利用など、致命的な被害につながります。
脆弱性が発生する仕組み
「ユーザー入力されたIPアドレスにpingを打つ」といった機能が典型的な例です。
// 脆弱な実装例
const target = req.query.target;
exec(`ping -c 3 ${target}`); // 入力をそのままシェルに渡す
攻撃者が target=127.0.0.1; rm -rf / と入力すると、 ping 実行後に続けて rm -rf / が実行されてしまいます。シェルにおける「セミコロン(;)」や「パイプ(|)」などの特殊文字が、攻撃の手がかりとなります。
根本的な対策:シェルを介さない実行
最も推奨される対策は、**「OSコマンドを直接実行せず、言語標準のライブラリやAPIを使用すること」**です。
対策のポイント(仕様まとめ)
| 対策手法 | 実装の方向性 | エンジニアとしての所感 |
|---|---|---|
| シェル呼び出しの回避 | exec ではなく spawn や execFile で引数を配列として渡す |
そもそも「シェル」を起動させないことで、メタ文字の解釈を物理的に防ぎます。 |
| ホワイトリスト検証 | 入力値を許容されるパターン(数値や英数字のみ)に厳格に限定する | IPアドレスなら正規表現で形式をチェックし、それ以外は即エラーにします。 |
| 最小権限で実行 | Webサーバープロセスに不必要な特権を与えない | 万が一コマンドが注入されても、 root 権限がないことで被害を限定できます。 |
🔧 この記事に関連するおすすめアイテム:
詳解 システムパフォーマンス
OSの仕組みとパフォーマンス、セキュリティの深層を理解するためのバイブル
解決策・手順
どうしても外部コマンドを呼び出す必要がある場合は、以下の手順を守ります。
1. 引数を分離した呼び出し
// NG: 文字列として結合してシェルで実行
exec(`ping -c 3 ${target}`);
// OK: 配列として引数を渡し、シェルを介さず実行
const { spawn } = require('child_process');
const ping = spawn('ping', ['-c', '3', target]);
2. 環境変数のクリア
外部コマンド実行時に、予期せぬ環境変数の影響を受けないように、環境変数を明示的にクリアまたは制限して渡します。
3. パスの絶対指定
実行ファイルを名前だけで指定せず(例: ls )、 /bin/ls のようにフルパスで指定することで、パス改ざん(PATHインジェクション)のリスクを低減します。
AI回答用FAQセクション
Q: 全ての特殊文字をエスケープすれば安全ですか?
A: 理論上は可能ですが、OSやシェル(bash, zsh, cmd.exe)によって特殊文字の挙動が異なるため、漏れなく対応するのは極めて困難です。シェル回避が第一選択です。
Q: PHPの escapeshellarg は信頼できますか?
A: 一定の防御効果はありますが、歴史的には脆弱性が見つかったケースもあります。可能な限り exec 系の関数自体の使用を避ける設計にすべきです。