SQLインジェクション攻撃について
SQLインジェクション(SQL Injection)は、データベースと連携するアプリケーションがユーザーからの入力を適切に処理せずにSQLクエリとして直接使用してしまうことによって発生する脆弱性です。攻撃者は、この脆弱性を利用して、SQLクエリを改ざんし、データベースのデータを不正に操作(例えば、データの漏洩、削除、変更)することができます。
脆弱なコード:
<?php
$username = $_GET['username'];
$password = $_GET['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result) > 0) {
echo "Login successful!";
} else {
echo "Invalid username or password.";
}
?>
攻撃手法:
攻撃者は、username
フィールドに' OR '1'='1
を入力し、password
フィールドに' OR '1'='1
を入力することで、以下のようにクエリが改ざんされます。
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '' OR '1'='1';
このクエリは常にtrue
を返し、攻撃者が認証を回避できるようになります。
脆弱なコード:
from flask import request
import sqlite3
username = request.args.get('username')
password = request.args.get('password')
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
if cursor.fetchone():
print("Login successful!")
else:
print("Invalid username or password.")
攻撃手法:
同様に、username
フィールドに' OR '1'='1
、password
フィールドに' OR '1'='1
を入力することで、クエリが改ざんされ、認証が突破されます。
脆弱なコード:
const express = require('express');
const app = express();
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'mydb'
});
app.get('/login', (req, res) => {
const username = req.query.username;
const password = req.query.password;
const query = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
connection.query(query, (error, results) => {
if (results.length > 0) {
res.send("Login successful!");
} else {
res.send("Invalid username or password.");
}
});
});
app.listen(3000);
攻撃手法:
同様に、username
フィールドに' OR '1'='1
、password
フィールドに' OR '1'='1
を入力することで、クエリが改ざんされ、ログインが許可されてしまいます。
脆弱なコード:
import java.sql.*;
public class SQLInjectionExample {
public static void main(String[] args) {
String username = args[0];
String password = args[1];
String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
if (rs.next()) {
System.out.println("Login successful!");
} else {
System.out.println("Invalid username or password.");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
攻撃手法:
Javaでも、username
フィールドに' OR '1'='1
、password
フィールドに' OR '1'='1
を入力することで、クエリが改ざんされ、認証を回避できます。
mysqli_prepare
、Pythonではcursor.execute(query, (param1, param2))
、Node.jsではmysql2
モジュールのprepared statements
、JavaではPreparedStatement
を使用します。まとめ: SQLインジェクションは、ユーザー入力を適切に処理しない場合に発生する脆弱性で、データベースの不正操作を可能にする危険な攻撃です。プリペアドステートメントの使用、入力サニタイズ、ユーザー権限の最小化などの防止策を適用することで、この脆弱性を効果的に防ぐことが可能です。各言語に共通して有効な対策であり、どのプラットフォームでもこれらのベストプラクティスを実装することが推奨されます。