[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. 参考情報
- OWASP SQL Injection
- PHP公式マニュアル「mysqli::prepare」
Discussion