9485
PHPでの

```

    sprintf("SELECT * FROM table WHERE id = %d", $value);
    
    sprintf("SELECT * FROM table WHERE id = %s", escape($value));
    
    sprintf("SELECT * FROM table WHERE id = '%s'", escape($value));
    
```

の3つのコードについて、2行目のコードでSQLインジェクション脆弱性が生じ、1行目と3行目は問題がないのはどのような理由でしょうか

ここで`escape()`は値をSQLの文字列リテラル(のシングルクオーテーションの内側)としてエスケープする`mysqli_real_escape_string`のような関数とします。
CC BY-SA 3.0
2015-04-23T00:29:48.083
9484
2015-04-23T08:14:33.507
5793
question
php sql
PHPのsprintfによるSQL組み立てで脆弱性が生じる例
1番目

```

    sprintf("SELECT * FROM table WHERE id = %d", $value);
    
```

`$value`にどのようなデータが入っていようが、PHPの「親切な」型変換により数値に変換されます。`escape()`が無くても問題ありません。

```

    "123"    => 123
    "  123"  => 123
    "123abc" => 123
    "abc"    => 0
    " "      => 0
    ""       => 0
    null     => 0
    
```

ただし、4つめ以降の例はアプリケーションとしては意図しない動作になるでしょうから、その観点では事前にバリデーションが必要です。

2番目

```

    sprintf("SELECT * FROM table WHERE id = %s", escape($value));
    
```

1番目の`%d`を`%s`に書き換え`escape()`を付加した例です。$valueはリテラルではなくSQL構文の一部として展開されます。例えば`$value`が`1
or 1 = 1`であれば

```

    SELECT * FROM table WHERE id = 1 or 1 = 1
    
```

となります。`escape()`は文字列リテラルのためのエスケープですから、この場合SQLインジェクション防止には役に立ちません。上記は適切にエスケープが行われた結果です。

3番目

```

    sprintf("SELECT * FROM table WHERE id = '%s'", escape($value));
    
```

`$value`は文字列リテラルとして展開されます。`escape()`で文字列リテラルとして正当な形式にエスケープされるので安全です。

以上はSELECTを例にしていますが、INSERTであってもサブクエリを用いたりRDBによっては複文が使えたりするので、同様に攻撃が可能です。

## `sprintf`を使用したSQL組み立ての問題

このように、`sprintf`でのSQL組み立ては、

  * 数値型と文字型で書式指定子を確実に指定する。
  * `%s`で受ける場合は、`'%s'`とシングルクオーテーションを忘れてはいけない
  * エスケープ処理を確実に行わなければいけない(ただし`%d`で受けるときは必須ではない)

と言うことにプログラマが注意する必要があります。不注意によりこれらを間違えると脆弱性が生じます。

プレースホルダを使用する場合は`SELECT * FROM table WHERE id =
?`のように文字列であっても引用符無しで`?`を指定しますがこれに引っ張られて裸の`%s`を指定したり、`%d`を用いた際の型変換によるSQLインジェクション防止を拡大解釈し、`sprintf`を用いるときはエスケープ不要であると誤解している例もあります。

プレースホルダを用いたバインドメカニズムを使うべき、とされるのは、仕組み上安全なことが保証されており、プログラマの不注意により脆弱性が生じるようなことがないからです。そのあたりの詳細はIPAの[安全なSQLの組み立て方](http://www.ipa.go.jp/security/vuln/websecurity.html)を参照してください。
CC BY-SA 3.0
2015-04-23T00:29:48.083
9485
2015-04-23T08:14:33.507
2015-04-23T08:14:33.507
5793
5793
9484
answer