0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PHP SQLインジェクションを意識する 初学者向け

Last updated at Posted at 2022-02-09

※PHP初学者向けコンテンツです。
内容に誤りがある場合はご指摘頂けますと大変ありがたいです。

PHP学習時に何か作成しながら勉強しようと思っている際に、
DB連携を行う時、サイトに書いてあるコードをコピペして動けるようになったと満足していたあの頃の自分へ向けて書きます。

PHPを用いてDB連携を行う僕へ

例えば僕はこんなプログラムを書いていた。

index.php

画面上でユーザーが入力するためのフォーム画面(簡易版)です。
<form action="<?php $_SERVER['REQUEST_URI']; ?>" method="POST">
    <input type="text" name="category_id">
    <input type="submit" value="ボタン">
</form>

<?php

//入力情報がPOSTであった場合ifの中の処理を行うように定義
//issetとは簡単には、存在した場合処理trueとして処理するもの!
//!issetとは簡単には、存在しない場合処理trueとして処理するもの!
if(isset($_POST['category_id'])) {
    
    //form(UI)から入力された値を$shop_idに格納するよう定義
    $shop_id = $_POST['category_id'];
    
    //以下DB接続詳細項目記載
    $user = '接続するDBに対して権限あるユーザー名';
    $pass = '接続するDBに対して権限あるユーザーのPASSWORD';
    $host = 'localhost';
    $dbName = '接続するDB名';

    //上でDB情報を定義した関数を1つの関数にまとめて使いやすくする。
    $dsh = "mysql:host={$host};port=8080;dbname={$dbName};";
    $cone = new PDO($dsh, $user, $pass);
    $cone->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    $cone->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    //$coneで接続定義したDBへSQLを実行するためのSQLを記載
    $psq = $cone->exec("select * from DB名.テーブル名 where category_id = :c_id;");
    //データ取得後にどの関数へどのように格納するかを定義(id,'値',オプション);
    $psq->bindValue(':c_id',$category_id,PDO::PARAM_INT);
    //実際にSQLを実行
    $psq->execute();
    
    //上記で実行されたデータを取得して(ここではfetch())$resultに格納
    //resultの日本語訳 = 結果
    $result = $psq->fetch();

    //取得データ格納されている$resultを用いて出力
        echo "アイス味は[{$result['type']}]です。";
}
?>

SQLインジェクションとは

簡単に、
「UI画面であったり、容易にDBデータをいじられる(いたずらできる)状態」のこと

最初のプログラムでダメだった点

index.php

//この部分
$psq = $cone->exec("select * from DB名.テーブル名 where category_id = :c_id;");

//対策として、以下にする必要がある。
$psq = $cone->prepare("select * from DB名.テーブル名 where category_id = :c_id;");

補足prepare
    //prepareが対応できないSQL構文を擬似的にprepareで対応するようにする定義
    $cone->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);

今回のケースおさらい

文章となるが、以下読むべし!

【prepare】
prepare⇒bindValue⇒execute
①ユーザーが入力した変動値(フォーム画面より)を取得すると、
 一旦すぐにSQL実行ではなく、DB上でSQL構文解析、書き換えが行われます。
後は、「指定した変動値(:id)」と「実行命令」が来たらSQLが実行されるまでの状態の処理が行われています。

② bindValueにて、データ型を指定したい場合はbindValueを使用します。
 →デフォルト値はPARAM_STR(文字列型)でした。文字列型でもいいなら省略しても良いと思います。
※bindValueを省略しても処理は実行されます。

③やっとここで、SQL実行が行われます!
※bindValueが省略されている場合は、execute(変動値 =>フォーム画面から受け取ったデータ格納されている関数);とする必要があります。
 prepare(プリペアド)で構文チェック書き換えが行われたSQLの処理を実行します!

補足:
prepareでは、①でSQL構文解析・書き換えが行われており、同じ構文が繰り返しよく使われる場合は、構文解析作業が繰り返されることを防止され、パフォーマンス向上というメリットもあります。

【query exec】
有無を言わずにSQL実行!!truncateでも何でも!
変動値のないSQL構文の場合で尚且つ単発処理の場合は、利用しても良いのかもしれません。

補足 PARAM_?

PARAM_ほにゃららには以下のような種類があります。
SQL文の対象部分をどのデータ型で表現するかを決めることができます。

PDO::PARAM_STR ・・・デフォルトで文字列型
PDO::PARAM_INT ・・・数値型
PDO::PARAM_BOOL ・・・BOOLERN型
PDO::PARAM_NULL ・・・NULL型

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?