26768
以下のようなプリペアードステートメントを作りました。

```

    $ps=$db->prepare("SELECT id, name, time FROM comment WHERE user = $area ORDER BY $order $desc");
    
```

defaultでは

```

    $area="1 or 1=1";
    $order='time';
    $desc="";
    
```

が入っており、`SELECT id, name, time FROM comment WHERE user = 1 or 1=1 ORDER BY
time;`が実行されます。

質問1  
WHERE部分とORDER部分において、`:t_time`のように`bindParam`を実行しようと思ったのですが、  
上手くいきませんでした。普通に変数にしたら出来たのですが、これは普通のやり方でしょうか？

質問2  
`$area`, `$order`, `$desc`をGET送信で受け取る場合、SQLインジェクションなどのセキュリティ上の問題は発生するのでしょうか。  
自分で試したところ、問題なさそうだったのですが。。。
CC BY-SA 3.0
2016-06-15T07:45:35.527
26763
2016-06-15T18:33:26.777
2016-06-15T18:33:26.777
10492
15279
question
php mysql security
PHPのプリペアードステートメントのセキュリティについて
こんにちは。

回答1

> 普通に変数にしたら出来たのですが、これは普通のやり方でしょうか？

普通ではありません。$areaは引用符で囲っていないということは、数値でしょうか。その場合、例えば以下のようにします。数値の場合は、バインドする値をintなどにキャストするほうがいいです。

```

    $ps=$db->prepare("SELECT id, name, time FROM user WHERE user = :area ORDER BY $order $desc");
    $ps->bindValue(':area', (int)$area, PDO::PARAM_INT);
    $ps->execute();
    
```

回答2

> $area, $order, $descをGET送信で受け取る場合、SQLインジェクションなどのセキュリティ上の問題は発生するのでしょうか。  
>  自分で試したところ、問題なさそうだったのですが。。。

そんなことはありません。攻撃はできます。以下、プレースホルダを使っていない元のスクリプトを前提します。  
まず、$areaに以下のように UNION を使って別のテーブルを指定できます。

```

    $area = "0 UNION SELECT 0, concat(id, ':', pwd), 0 FROM users #";
    
```

id列とtime列は文字列型でないと仮定しました。すると、実行されるSQL文は下記となります。

```

    SELECT id, name, time FROM user WHERE user = 0 UNION SELECT 0, concat(id, ':', pwd), 0 FROM users #  ORDER BY time asc
    
```

以下のように、別テーブルからIDとパスワードを読み出すことができます。

```

    0   alice:123456   0
    0   bob:dusifudos   0
    0   carol:password   0
    
```

次に、PDO+MySQLであれば、以下のように複文を指定できます。

```

    $area = "0; DELETE FROM user #";
    
```

呼び出されるSQL文は下記のようになり、userテーブルの行がすべて削除されます。

```

    SELECT id, name, time FROM user WHERE user = 0; DELETE FROM user #  ORDER BY time asc
    
```

また、$orderや$descを使った攻撃は少し難しくなりますが、先ほど同様に複文を使った攻撃は可能です。また、ORDER
BYの後には式が書けることから、その式を複雑に変化させることにより攻撃は可能です。以下のスライドでは、その方法を説明していますが、ややこしい攻撃なので理解が難しいかもしれません。

[Rails SQL Injection Examplesの紹介](http://www.slideshare.net/ockeghem/rails-
sql-injection-examples)

あるいは、ブラインドSQLインジェクションという方法も可能です。ブラインドSQLインジェクションについては以下のブログ記事を参照下さい。

[ブラインドSQLインジェクションのスクリプトをPHPで書いたよ](http://blog.tokumaru.org/2012/12/blind-sql-
injection-php-exploit.html)

対策ですが、$areaについてはプレースホルダを使うこと。$orderと$descはとり得る値は決まっているため、それをホワイトリストとしてバリデーションすることで対策になります。
CC BY-SA 3.0
2016-06-15T11:34:29.853
26768
2016-06-15T11:34:29.853
781
26763
answer