SQL Injection

概要

  • 脆弱性の名前: SQL Injection
  • 問題の要点: Webアプリケーションが、ユーザーからの入力を適切に検証せずにSQLクエリに組み込むことで、攻撃者がデータベースを不正に操作できる脆弱性。
  • よくある発生シーン: フォーム入力、URLパラメータ、Cookieなど、ユーザーが提供するデータがデータベースクエリで使用される箇所

背景

SQL Injectionは、Webアプリケーション黎明期から存在する古典的な脆弱性ですが、未だに多くのWebサイトで発見されています。
データベースへのアクセスを伴うWebアプリケーションは多いため、SQL Injectionの対策が不十分な場合、深刻なセキュリティリスクとなります。
過去には、SQL Injectionを悪用した大規模な情報漏洩事件が多数発生しており、企業や組織に大きな損害を与えています。

セキュリティ上のリスク

  • データベース内の機密情報(個人情報、クレジットカード情報など)の漏洩。
  • データベースの改ざんや破壊。
  • Webサイトの改ざんや不正なコンテンツの表示。
  • データベースサーバーのOSコマンド実行。

対処方法の具体例

PHP

誤った設定例

ユーザーからの入力をエスケープせずにSQLクエリに組み込む例:

<?php
// 誤った例: エスケープ処理なし
$username = $_GET['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
$result = mysqli_query($conn, $query);
?>

正しい設定例

プリペアドステートメントを使用し、ユーザーからの入力を安全に処理する例:

<?php
// 正しい例: プリペアドステートメントを使用
$username = $_GET['username'];
$stmt = mysqli_prepare($conn, "SELECT * FROM users WHERE username = ?");
mysqli_stmt_bind_param($stmt, "s", $username);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
?>

Python

誤った設定例

ユーザーからの入力をエスケープせずにSQLクエリに組み込む例:

# 誤った例
username = request.args.get('username')
query = "SELECT * FROM users WHERE username = '%s'" % username
cursor.execute(query)

正しい設定例

プレースホルダーを使用し、ユーザーからの入力を安全に処理する例:

# 正しい例
username = request.args.get('username')
query = "SELECT * FROM users WHERE username = %s"
cursor.execute(query, (username,))

Java

誤った設定例

ユーザーからの入力をエスケープせずにSQLクエリに組み込む例:

// 誤った例
String username = request.getParameter("username");
String query = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);

正しい設定例

プリペアドステートメントを使用し、ユーザーからの入力を安全に処理する例:

// 正しい例
String username = request.getParameter("username");
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();

データベース

誤った設定例

データベースユーザーに過剰な権限を与えてしまう例:

正しい設定例

データベースユーザーに必要な最小限の権限のみを付与する:

AWS

誤った設定例

RDSインスタンスへのアクセス制御が不十分な例:

正しい設定例

セキュリティグループを使用して、RDSインスタンスへのアクセスを制限する:

検出方法

OWASP ZAPでの出力例

  • Alert 名: SQL Injection
  • リスク: High
  • URL: SQL Injectionが可能なURL
  • パラメータ: 悪用可能なパラメータ
  • 詳細: 脆弱性が存在する場所と、悪用方法に関する情報

手動再現例

  1. WebサイトのフォームやURLパラメータに、SQL Injectionのテスト文字列(例:' OR '1'='1)を入力します。
  2. エラーメッセージやWebサイトの挙動を観察し、SQL Injectionが成功するかどうかを確認します。

まとめ

  • CVSS 基本値: 10.0 (Critical)
  • 運用チームや開発者が意識すべきポイント:
    • ユーザーからの入力を常に検証し、エスケープする。
    • プリペアドステートメントやパラメータ化されたクエリを使用する。
    • データベースユーザーに必要な最小限の権限のみを付与する。
    • Webアプリケーションファイアウォール(WAF)を導入し、SQL Injection攻撃を防御する。
    • 定期的にペネトレーションテストを実施し、脆弱性を特定する。
  • 再発防止:
    • 開発プロセス全体でセキュリティを考慮する(Security by Design)。
    • コードレビューを実施し、SQL Injectionのリスクを早期に発見する。
    • 自動脆弱性診断ツールを導入し、定期的にスキャンを行う。
    • 開発者向けのセキュリティトレーニングを実施する。

補足資料・参考URL

以上の対策と検出方法を活用して、SQL Injectionのリスクを低減してください。