質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

  • PHP

    21372questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

PDOのSQLインジェクション対策について

解決済

回答 5

投稿

  • 評価
  • クリップ 6
  • VIEW 2,855

taishi_574

score 29

PDOのSQLインジェクション対策について調べていて疑問に思ったことがあるので質問です。

まず、私が考えているPDOにおけるSQLインジェクションは、
「フォームなどユーザーが入力できる箇所がある場合SQL文でデータベースを攻撃される危険があるため:や?を使用するか、アルファベットを受け付けないなどの処理をする」
というものです。
まずこれが間違っていたら教えていただけると幸いです。

いろいろなサイトを見ていると、下の様に変数を直接SQL文の中に入れるのは危険なので

$id=2;
$sql="SELECT * FROM table WHERE id > ${id}";


下のようにしてSQLインジェクション対策をしましょう!
などと書いていますが、何が危険なのかがいまいち分かりません。

$sql="SELECT * FROM table WHERE id=:id";

下のようにユーザーが入力をできる箇所のものならSQLインジェクション対策は必要かと思うのですが(この場合も引数には数字しか使わずctype_alphaでチェックすればいいのではないかと考えます)、それ以外の入力できる箇所がない場合は一番上のように変数を直接書いてもいいのではないでしょうか?

$sql="SELECT * FROM table WHERE id = ".$_GET["id"];

私が、考えている以外に脆弱性があるのなら教えていただけると幸いです。
よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+17

ご指摘のように、SQL文の一部に埋め込む変数が数値のみあるいは英字のみであることが確実であれば、SQLインジェクション脆弱になることはまずありません。しかし、プレースホルダ(:idの部分)を使ってSQLインジェクション対策をしましょうというのは、世界的なコンセンサスになっています。例えば、以下の記事をお読み下さい。

OWASPのSQLインジェクション対策方針を読んで「おまえは俺か」と思った

OWASPというのは、ウェブアプリケーションセキュリティの世界的な団体ですが、エスケープや入力値検証(バリデーション)による対策は完全なものにするとが難しいとした上で、プレースホルダによる対策を推奨しています。

冒頭で、数値のみあるいは英字のみであればSQLインジェクション脆弱性になることはまずないと書きましたが、変数の内容がメールアドレスであればどうでしょうか? 一般的に使われているメールアドレスは、英数字とハイフン、アンダースコア、アットマーク、ドットくらいしか使わないので、SQLインジェクション脆弱になることはないと思いがちですが、メールアドレスの規約であるRFC5322に準拠したメールアドレスであれば、SQLインジェクション攻撃が可能です。

XSSとSQLインジェクションの両方が可能なRFC5322適合のメールアドレス

つまり、自明な範囲を少し越えると、攻撃が可能になってしまう場合があるということです。
また、SQLインジェクション脆弱性が非常に危険であることもあらためて強調しておきたい内容です。以下の記事のように、SQLインジェクション脆弱性を作り込んでしまった結果、民事訴訟で 2000万円以上の損害賠償が課せられた判決(確定)があります。

SQLインジェクション対策もれの責任を開発会社に問う判決

このため、ごくわずかでもSQLインジェクション脆弱性が入り込む要素は取り除きたいところです。
そして、たとえば所属企業の社長が、上記の判決の記事を読んで、「我が社の開発コードにSQLインジェクション脆弱性はないか、再確認せよ」という指示があったとします。そして、例示されたSQL文を再確認したとします。

$sql="SELECT * FROM table WHERE id > ${id}";

ミクロで見ると、SQLインジェクション脆弱性があるように見えます。しかし、すぐ上を見ると、$id = 2; があるので、SQLインジェクションではないことがわかります。
しかし、この例はいくらなんでも単純すぎますよよね。実際には、もう少し上まで見ないとSQLインジェクションがないことは分からない場合が多いでしょう。$idをフォームのバリデーションで数字のみであることを確認していたとすると、バリデーションはソース上では全然別の箇所に書かれているかもしれません。そうなると、確認には時間が掛かりますし、確認漏れの心配も出てきます。

つまり、プログラムは書きっぱなしになることは稀で、アプリケーションのライフサイクルにわたって保守していくものですし、SQLインジェクションの可能性をわずかでも取り除くためには、下記の特性が重要なのです。

  • SQLインジェクションがないことが一目瞭然わかること

プレースホルダを使ったソースコードでは、SQLインジェクションがないことが一目瞭然で分かります。このような書き方で統一することで、わずかでもSQLインジェクション脆弱性が混入する余地をなくし、保守の際にも、一々SQLインジェクション脆弱性の心配をしなくてもすむことになります。

前述のように、SQLインジェクション対策は、技術的には複数の方法があるにも関わらず、プレースホルダによる方法に統一することが世界的な潮流になっています。それは、上記のような背景があるからだと考えます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/28 14:18

    詳しい回答ありがとうございます。

    疑問に思っていた事が解決しました!

    ありがとうございました。

    キャンセル

+5

そのSQLが決まった箇所でしか呼ばれず、その状態が未来に渡って不変なのであれば対応は必要ないかもしれません。
また、where句に設定される値が、「数字しか使わず」、かつ「必ず数値であること」をプログラムでチェックしているのであれば

しかし、対策を施していないSQLであるかどうかを、そのSQLを発行するプログラムが常に意識しなければいけないのは、大変なのではないでしょうか。SQLを使うロジックを再利用する時の妨げにもなる気がします。
また、入力に文字列があった場合にもチェックは必要でしょうから、いちいち、意識するよりもよりセキュアな設計に統一したほうが、開発効率も良いと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/23 18:47

    回答ありがとうございます。
    脆弱性云々より、開発効率や汎用性に問題ありということですね。

    そう言われてみればそうですね。
    現在はこの仕様で問題ないのですが、再利用するときなどの事も考えた方がいいですね。

    キャンセル

+2

冗長な書き方をしていると変数の中身に何が入っているか
いちいちチェックなんかしないですからね。
何が入っていてもとりあえず安心という意味ではプレースホルダは
役に立つと思いますよ
まぁキャストしたり、sprintfしたりでもいいですけど
結局それってインジェクション対策をしているってことで
あえてプレースホルダを否定する理由にはなっていません

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

$id=2;
$sql="SELECT * FROM table WHERE id > ${id}";


こういうのは最初から

$sql="SELECT * FROM table WHERE id > 2";


でいいと思います。
「変数が危険」なのは、あくまでPOSTやGETされた情報やセッション、クッキー等を変数化する場合かと思います。

安全なウェブサイトの作り方  
http://www.ipa.go.jp/security/vuln/websecurity.html 
安全なSQLの呼び出し方  
http://www.ipa.go.jp/files/000017320.pdf

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

たとえば、このような場合は変数で管理するしかないでしょう。

$flag= some_func(); // 外部から来る値

$dir = $flag ? 'ASC' : 'DESC';

// $flagが何であろうと、$dirには'ASC'か'DESC'しか入らない

$sql = "SELECT (中略) ORDER BY column $dir "; 

このように、スコープ内で「何が渡るかはっきりしている場合」には、変数に分けたからといって脆弱になることはありません。

ただ、一歩関数を越えるようなことになれば、(privateで呼べる箇所が限られているものならともかく)どんな呼び出し方をするかわかりません。文字列以外のものを要求するならタイプヒントで弾いてしまうのも方法としてありですが、文字列に「安全な値だけ渡してください」なんていうインターフェースを作ってしまうことは危険極まりません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • PHP

    21372questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。