コマンドインジェクション
まずはコマンドインジェクションそのものについて見ていきましょう。実際の動作を理解しやすくするために、いくつかの異なる例に焦点を当てます。復習として、コマンドインジェクションの脆弱性は、以下のような関数のように、ユーザー入力がオペレーティングシステムのコマンドの一部として使用される場合に発生します。
let ip = request.params.ipAddress;
system("ping " + ip);
ユーザーがIPアドレスとして「8.8.8.8」を入力した場合、実行されるコマンドは「ping 8.8.8.8」となり、期待通りの動作をします。しかし、ユーザーが「8.8.8.8 && ls /etc/」と入力した場合、このコマンドは単にIPアドレス8.8.8.8へpingを打つだけでなく、「/etc/」フォルダに対して「ls」コマンドも実行してしまいます。
緩和策
コマンドインジェクション攻撃の深刻さを踏まえ、システムコマンドを扱う際には、まず以下の重要な問いかけを行う必要があります。
- そのコマンドを本当に呼び出す必要がありますか?最善の防御策は、システムコマンドを一切呼び出さないことです。
- システムコマンドを使わずに同じ結果を得られるライブラリやバインディングはありますか?
- コマンド自体にデータを渡すのではなく、標準入力(Standard In)を通じてデータを渡すことはできませんか?
これらが不可能な場合は、パラメータ化が重要になります。
例
実践的な理解を深めるために、いくつかの言語での例を紹介します。
パラメータ化を行わない場合、コマンドインジェクションに対して脆弱になります。
string folder = "/tmp/ && ifconfig";
string cmd = "\"ls " + folder +"\"";
// 安全ではありません: `ls` と `ifconfig` の両方のコマンドが実行されます
System.Diagnostics.Process.Start("bash", "-c " + cmd);
C# - 安全な実装
コマンドをパラメータのリストとして提供することで、コマンドがパラメータ化され、コマンドインジェクションから保護されます。
string folder = "/tmp/ && ifconfig";
List<string> arguments = new List<string>() {"-c", "ls", folder};
// 安全: ifconfigコマンドは実行されません
System.Diagnostics.Process.Start("bash", arguments);
Java - 安全でない実装
パラメータ化を行わない場合、コマンドインジェクションに対して脆弱になります。
String folder = "/tmp/ && ifconfig";
// 安全ではありません: `ls` と `ifconfig` の両方のコマンドが実行されます
ProcessBuilder b = new ProcessBuilder("bash -c ls " + folder);
Process p = pb.start();
Java - 安全な実装
コマンドをパラメータのリストとして提供することで、コマンドがパラメータ化され、コマンドインジェクションから保護されます。
String folder = "/tmp/ && ifconfig";
// 安全:ifconfigコマンドは実行されません
ProcessBuilder b = new ProcessBuilder("bash", "-c", "ls", folder);
Process p = pb.start();
Javascript - 安全ではない実装
パラメータ化を行わない場合、コマンドインジェクションに対して脆弱になります。
const { exec } = require("child_process");
const folder = "/tmp/ && ifconfig";
// 安全ではない実装:`ls`と`ifconfig`の両方のコマンドが実行されます
const ls = exec("bash -c ls " + folder, (error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
});
Javascript - 安全な実装
const { spawn } = require("child_process");
const folder = "/tmp/ && ifconfig";
// 安全:ifconfigコマンドは実行されません
const ls = spawn("bash", ["-c", "ls", folder]);
ls.stdout.on("data", data => {
console.log(`stdout: ${data}`);
});
Python - セキュリティ上の脆弱性あり
パラメータ化を使用していないため、コマンドインジェクションに対して脆弱です。
import subprocess
folder = "/tmp/ && ifconfig"
# 安全ではない実装:`ls`と`ifconfig`の両方のコマンドが実行されます
subprocess.run("bash -c ls " + folder, shell=True)
Python - セキュリティ対策済み
コマンドをパラメータのリストとして提供することで、コマンドがパラメータ化され、コマンドインジェクションから保護されます。
import subprocess
folder = "/tmp/ && ifconfig"
# 安全:ifconfigコマンドは実行されません
subprocess.run(["bash", "-c", "ls", folder])
実践的なセキュアコーディング
OWASP Top 10のようなソフトウェアの脆弱性を理解し軽減するためのセキュアコーディングガイドラインを確認しましょう。また、実践的なアプリシミュレーションを通じて学べるトレーニングミッションにもぜひ挑戦してください。