🌐

[PHP] SQLインジェクションについて

に公開

SQLインジェクションについて

今回は「SQLインジェクション」について解説します。
Webアプリ開発やデータベースを扱うなら絶対に知っておくべきセキュリティリスクなので、この記事でサクッと理解してしまいましょう。

注意:SQLインジェクションを他人のサーバー・サービスなどで実行することは犯罪です。


1. SQLインジェクションとは?

SQLインジェクション(SQL Injection)とは、Webアプリの入力フォームやURLパラメータなどに悪意あるSQL文を埋め込んで、データベースに不正アクセスや操作を行う攻撃手法のこと。

具体的には、ユーザー入力を適切に処理しないと、「ログイン認証のSQL文に意図しないコードが挿入されて、管理者権限でログインできてしまう」みたいなことが起きます。


2. なぜ起きるのか?

SQL文を組み立てる際に、ユーザーの入力値をそのまま文字列連結で組み込んでしまうため。
これにより' OR '1'='1のような条件をSQLに埋め込まれ、常に真になる条件が作られてしまいます。


3. 危険なサンプルコード(PHP + MySQL)

<?php
// ユーザー入力(例: ?username=admin&password=1234)
$username = $_GET['username'];
$password = $_GET['password'];

// 危険 直接SQL文に埋め込み
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

$conn = new mysqli('localhost', 'user', 'pass', 'dbname');
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    echo "ログインに成功しました";
} else {
    echo "ログインに失敗しました";
}
?>

このままだと、例えばadmin' OR '1'='1' --を入力すると

SELECT * FROM users WHERE username = 'admin' OR '1'='1' -- ' AND password = ''

SQLのコメントアウト--でパスワード条件を無効化できてしまい、
パスワード無しでadminログインができてしまいます。


4. 改善策1: プレースホルダー(プリペアドステートメント)を使う

<?php
$username = $_GET['username'];
$password = $_GET['password'];

$conn = new mysqli('localhost', 'user', 'pass', 'dbname');

// プリペアドステートメントを用意
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();

$result = $stmt->get_result();

if ($result->num_rows > 0) {
    echo "ログインに成功しました";
} else {
    echo "ログインに失敗しました";
}

$stmt->close();
$conn->close();
?>

こうすることで、SQL文とデータを分離し、ユーザー入力に悪意あるコードが混入してもSQLとして解釈されないようになります。


5. 改善策2: ORMやフレームワークの利用

PHPならLaravel、PythonならDjangoやSQLAlchemyなど、ORM(Object Relational Mapping)やフレームワークを使うと安全にSQLを扱えます。
内部でプレースホルダーなどの仕組みを自動で使ってくれるので、SQLインジェクションのリスクが大幅に減ります。


6. まとめ

ポイント 内容
SQLインジェクションとは ユーザー入力に悪意あるSQL文を埋め込む攻撃手法
原因 ユーザー入力をそのままSQLに埋め込むこと
危険 不正ログイン、情報漏えい、データ破壊など
対策 プリペアドステートメント(プレースホルダー)を使う
その他の対策 ORMやフレームワークの利用、入力値の検証やエスケープ

7. 参考情報

Discussion