【PHP】mysqliのプリペアドステートメント記述(SQLインジェクション対策)
2023-06-03 749 1816PHPでのSQLインジェクション対策ならプリペアドステートメントが有名です。
(プリペアド・ステートメントは静的プレースホルダ、バインド機構と呼ぶ場合もあるようです)
PDO派ではなく、mysqli派の方へ向けたプリペアドステートメントの記述方法の紹介です。
コードを見ればなんとなく分かると思います。
prepare関数にて「?」を仕掛けた数だけ、bind_param関数の引数の数に関係します。
<削除 DELETE>
<?php
$id = htmlspecialchars($_POST["id"]);
$stmt = $mysqli->prepare("DELETE FROM `topics` WHERE `id` = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
$stmt->close();
?>
<追加 INSERT>
<?php
$sql_into = "`id`,`cate`,`sub`,`body`,`link`,`updated`,`created`,`flag`";
$sql_valu = "null,?,?,?,?,?,NOW(),1";
$stmt = $mysqli->prepare("INSERT INTO `topics` ({$sql_into}) VALUES ({$sql_valu})");
$stmt->bind_param("issss",$cate, $sub, $body, $link, $updated);
$stmt->execute();
$new_id = $mysqli->insert_id;
?>
bind_param関数は一つ目の引数に、「?」の数だけ「i(integar:数値)」か「s(string:文字列)」を指定しています。「f(小数点あり)」もあります。date型は「s」を指定します。iとsだけで大体はOKでしょう。
プリペアドステートメントの記述でもinsert_idが取得できました。
<更新 UPDATE>
<?php
$sql_update = "
`cate` = ?,
`sub` = ?,
`body` = ?,
`link` = ?,
`updated` = ?,
`flag` = ?
";
$stmt = $mysqli->prepare("UPDATE `topics` SET {$sql_update} WHERE `id` = ?");
$stmt->bind_param("issssii", $cate, $sub, $body, $link, $updated, $flag, $id);
$stmt->execute();
?>
ちょっとややこしい書き方に見えるかもしれません。
「?」の数とbind_paramの引数を照らし合わせてコードを見れば意味が分かると思います。
<取得 SELECT>
<?php
$id = htmlspecialchars($_POST["id"]);
$stmt = $mysqli->prepare("SELECT * FROM `topics` WHERE `id` = ? LIMIT 1");
$stmt->bind_param("i", $id);
$stmt->execute();
$row = fetch_all($stmt);
?>
配列で$rowにデータが返ります。
ここでポイントはfetch_all関数はユーザー定義です。
<プリペアドステートメントの結果を連想配列に変換する関数>
<?php参照「PHPのmysqli_stmtでfetchAllっぽいものを実現する方法」
function fetch_all(& $stmt) {
$hits = array();
$params = array();
$meta = $stmt->result_metadata();
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array(array($stmt, "bind_result"), $params);
while ($stmt->fetch()) {
$c = array();
foreach($row as $key => $val) {
$c[$key] = $val;
}
$hits = $c;
}
return $hits;
}
?>
以上がPHPのmysqliでのプリペアドステートメント記述法。
また作業をしている際に、需要の高そうなコードがありましたら、この記事に追記していきます。
SQLインジェクションは年々増えているとのことで、改ざんや個人情報の漏洩でクライアントに迷惑をかけてはいけませんので、しっかりとプリペアドステートメント(プレースホルダ)の記述でMySQLを操作していかないといけません。
formのaction値を空にするSQLインジェクション対策
サイトの自動巡回でformタグのあるページを探し、さらにactionの値を取得する。そして、action値のURLにDOS攻撃。というのが一般的に想定される悪徳業者のやり方なので、action値を空にするだけでも自動ボットによるURL取得を防げると思います。
<form method="post" action="">単純なコードになりますが、しないよりはマシという対策のひとつです。
<input type="text" name="mail">
<input type="password" name="pass">
<button type="button" class="exe">LOGIN</button>
</form>
<script>
$(".exe").click(function(){
$("form").attr("action","xxxx.php");
$("form").submit();
});
</script>
- 関連タグ:
- SQLインジェクション
- プリペアドステートメント
- プレースホルダ