【PHP】mysqliのプリペアドステートメント記述(SQLインジェクション対策)

2023-06-03    307   1938

PHPでの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
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_stmtでfetchAllっぽいものを実現する方法

以上が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>
単純なコードになりますが、しないよりはマシという対策のひとつです。

comment 登録なしでご自由にご入力いただけます(^^)ぜひぜひ記事のご感想をお聞かせ下さい。

お名前とコメントは入力必須です。

コメントの文字数が短すぎます。

この内容でコメントを送る
コメントをする

目が疲れている方向けにラジオ系Youtubeを始めました

オススメのPHPに関する記事

この記事がお役に立てましたら是非シェアのご協力お願いします。