大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

XAMPPでMySQLを使う その3

著者:北本 敦
公開日:2022/10/21
最終更新日:2022/11/29
カテゴリー:技術情報
タグ:

北本です。

前回は以下のようなPHPコードを紹介し、致命的な欠陥があると書いて終わりました。今回はその内容に具体的に触れていくことにします。前回からの続きなのでタイトルにはXAMPPやMySQLと書いていますが、今回の内容はそれらに特化したものではなくSQL・PHP全般に該当する内容かと思います。

test.php

早速ですが、欠陥が明らかになる操作をしてみます。都道府県のテキストボックスに以下の文字列を入力して「送信」ボタンをクリックしてみましょう。

何もない画面に遷移するはずです。

ではcitiesテーブル見てみましょう。

なんと、尼崎市が大阪府に編入されてしまっています!

というのも、以下のようなSELECT文とUPDATE文が実行されてしまったからです。

何もない画面が表示されたのは、SELECT文でprefecture = ”に該当するレコードをcitiesから取得しようとして1件も取得できなかったからです。そして、2つ目のUPDATE文が尼崎市のprefectureが大阪府に変更されてしまった原因です。例ではUPDATE文を実行させましたが、やろうと思えばINSERT文やDELETE文を忍び込ませてレコードの追加や削除をしたりテーブル自体を削除してしまったりすることもできるでしょう。

単純に文字列連結でSQL文を生成しているとこのような問題が起きてしまいます。典型的なSQLインジェクションの例です。

これを防ぐには以下のようなコードにします。

test.php

このコードだと、同様の文字列をテキストボックスに入力して送信しても、尼崎市のprefectureは大阪府に変更されないはずです。

変更点を見ていきましょう。
まず、パラメータの文字列をそのまま連結してwhere句を作成していましたが、そのパラメータの箇所を「:prefecture」、「:population_min」、「:population_max」といったプレースホルダに置き換えています。今回は「:」で開始する名前付きプレースホルダを使用していますが、「?」を使うことも可能です(詳細は次回に)。

また、PDOのqueryメソッドでSQL文を即時実行していたのをprepareメソッドを使用する形に変更しています。prepareメソッドを実行するとPDOStatementオブジェクトが返ってきますが、そのオブジェクトのexecuteメソッドを呼ぶとprepareでセットしたSQL文が実行されます。

executeを実行する前には、bindValueメソッドを実行していますが、ここでプレースホルダに値をセットしています。bindValueメソッドの第1引数については、名前付きプレースホルダを使用している場合はその文字列を指定します。第2引数にはプレースホルダにセットする値、第3引数は任意ですが値の型を指定します。

このようにbindValueでパラメータを反映するようにすれば、

のような値がテキストボックスに入力されていたとしても、その全体がシングルクオートで囲われた一つの文字列のように処理されるため、先程のようにUPDATE文が実行されてしまうようなことは起こりません。

次回はこれまでの内容の補足的なことを書こうと考えています。今回同様SQL・PHP全般に該当する内容になると思います。

    上に戻る