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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

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

Q&A

解決済

5回答

6589閲覧

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

taishi_574

総合スコア39

PHP

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

1グッド

6クリップ

投稿2017/01/23 09:10

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"];

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

ockeghem👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

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

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

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

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

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

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

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

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

SQL

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

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

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

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

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

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

投稿2017/01/23 14:24

ockeghem

総合スコア11701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taishi_574

2017/01/28 05:18

詳しい回答ありがとうございます。 疑問に思っていた事が解決しました! ありがとうございました。
guest

0

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

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

投稿2017/01/23 09:34

motuo

総合スコア3027

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taishi_574

2017/01/23 09:47

回答ありがとうございます。 脆弱性云々より、開発効率や汎用性に問題ありということですね。 そう言われてみればそうですね。 現在はこの仕様で問題ないのですが、再利用するときなどの事も考えた方がいいですね。
guest

0

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

投稿2017/01/23 09:44

yambejp

総合スコア114777

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

php

1$flag= some_func(); // 外部から来る値 2 3$dir = $flag ? 'ASC' : 'DESC'; 4 5// $flagが何であろうと、$dirには'ASC'か'DESC'しか入らない 6 7$sql = "SELECT (中略) ORDER BY column $dir ";

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

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

投稿2017/01/23 11:52

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

sql

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

こういうのは最初から

sql

1$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

投稿2017/01/23 09:43

takepieee

総合スコア686

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問