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

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

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

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

解決済

2回答

6249閲覧

CakePHPの$this->query()に数値をバインドさせたい

ia_isier

総合スコア29

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

0クリップ

投稿2015/11/09 02:44

編集2015/11/09 02:49

閲覧ありがとうございます。

CakePHPにおけるサニタイズ処理について質問させてください。
表題の通り、$this->query()に独自SQLを渡す際にPrepared Statementを利用したところ、
LIKE句など文字列を渡す部分については正常に動いたのですが、
LIMITやOFFSET句など数値型でバインドする必要のある部分でエラーが発生しました。

調べたところ、PDOのbindValue()はバインドする値が強制的に文字列に変換されてしまい、
それを防止するためにはbindValue()の第三引数にPDO::PARAM_INTを指定することで、
数値型をバインドさせることができるようです。

しかし、CakePHPのリファレンスに記載されている$this->query()メソッドの項にはそれらしき引数が見当たりません。
大人しくCakePHPのO/Rマッパー(find)を使えよ、という話ですが、
SQLが非常に複雑なため、なるべくアソシエーションにコストを割くことは避けたいのが現状です。

苦肉の策として、
「数値が入ることが確定しているのだから、数値型であることをバリデーションチェックした変数をSQL内に展開する」
という策を思いつきましたが、当方サーバーサイド初心者であるため、SQLインジェクション対策となっているかどうか不安です。

上記の件についてどなたかご教授いただけますと幸いです。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

お使いのDBが(MySQLなどのように)プリペアドステートメントをサポートしているのであれば、
クエリを実行する前にPDO::ATTR_EMULATE_PREPARESfalseに設定することで、問題を回避できると思います。

php

1$connection = $this->getDataSource()->getConnection(); 2$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 3 4$this->query(...);

確か、この属性はデフォルトでtrueだったと記憶しています。
http://php.net/manual/ja/pdo.setattribute.php

投稿2015/11/09 07:01

KiyoshiMotoki

総合スコア4791

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

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

ia_isier

2015/11/10 05:53

頂いた回答を元に値を設定してみたところ、無事に動きました! ありがとうございます!
guest

0

CakePHPの具体的な実装には回答出来ないのですが、

「数値が入ることが確定しているのだから、数値型であることをバリデーションチェックした変数をSQL内に展開する」

だと「バリデーションチェックし忘れ」が常に発生し得るため、機械的にSQLインジェクション対策が出来ていることを保証するのがとても難しくなります。

サニタイズは「データ出力時にその出力先に適した形(安全だと保障されている形)にエスケープする」と定義出来ますから、出力時に明示的に処理されないのはもやっとします。

なので私であれば、
「該当の変数を定数とマッピングさせ、定数値を使う」
「該当の変数を整数型に明示的にキャストしてSQLに展開する」
のどちらかの方法を取ると思います。
*バインドさせる方法があればそれがもちろんベストです。

投稿2015/11/09 03:27

tanat

総合スコア18709

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

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

ia_isier

2015/11/09 03:53

ご回答ありがとうございます! こんなに早く答えていただけるとは…助かります。 >>「該当の変数を定数とマッピングさせ、定数値を使う」 具体的な処理がイメージできなかったのですが、 数値型の変数の値に応じて、予め用意しておいた定数値をSQLに展開する という解釈で合っていますでしょうか…? >>「該当の変数を整数型に明示的にキャストしてSQLに展開する」 キャストするということは、 キャストが通ればその変数を展開し、 キャストできなかったケースでは例外処理などを行う、 ということですよね? この場合の処理とバリデーションチェックを挟む処理が同じものに見えたのですが、 どのような違いがあるのでしょうか…? (見当違いのことを言っていたら申し訳ありません) 私の理解力不足で何度も質問してしまい申し訳ありません。 よろしければご回答いただけますと嬉しいです。
tanat

2015/11/09 04:21

>>「該当の変数を定数とマッピングさせ、定数値を使う」 >具体的な処理がイメージできなかったのですが、 >数値型の変数の値に応じて、予め用意しておいた定数値をSQLに展開する >という解釈で合っていますでしょうか…? はい。大変めんどくさく、メンテナンスコストもかかってしまう方法ですが、定数値であれば安全であることを機械的に証明が可能です。 実際にはマッピングするクラスを作って、マッピング出来なければ例外を吐く様な形で連結すると思います。 >どのような違いがあるのでしょうか…? >(見当違いのことを言っていたら申し訳ありません) 今回のご質問からすると範囲が大きくなってしまい、過剰な形の回答になってしまっているようにも思います。 一応、以下に説明を書きますと・・・ (入力時)バリデーションと(出力時)サニタイジングでは役割が明確に違い(と私は考えている)ため、サニタイジングは機械的にチェック可能な方法で行われる必要があると考えています。 そのため、アプリケーション的に許容される値(数値の範囲など)はバリデーションで、既に行われるものという前提で、SQL展開時(出力時)には「キャストのみ」というサニタイジングを実施するのがベターだと考えています。 (入力時の)バリデーションに求めるものは「そのアプリケーションとしての値の正当性を入力時にチェックする」ことであって、出力先の都合を考えるのは責任範囲外だと考えます。 例えば、今回のlimit句とは少し離れますが、仮に「データとしてSQLとしては危険な文字を持たないといけない場合」、入力時のチェックでSQLとしては危険な文字である「'」や「;」をはじいてしまうとアプリケーションの要件を満たせなくなってしまいます。 また、今回のケースだと範囲指定を行うバリデーションが出力時に実行される場合、 処理毎に別のメソッドを呼び出すことになってしまい、機械的な判断がとても難しくなります。 この危険な文字列を安全な文字列に変換するのはバリデーションでは無く、サニタイジングであり、サニタイジングの役割は 「その出力先にとって安全なフォーマットであることが保障されるようにする」 です。 *** もちろんベストはPDO付属のprepare()によってバインドされる方法です *** サニタイズ(サニタイジング)については http://takagi-hiromitsu.jp/diary/20060115.html からの一連の流れが非常にためになりますので、ご一読いただくことをお勧めします。 IPAの「安全なウェブサイトの作り方」もぜひ・ https://www.ipa.go.jp/security/vuln/websecurity.html
ia_isier

2015/11/10 05:57

ご回答ありがとうございます。 余計な質問を重ねてしまい申し訳ありません。 そもそも私がバリデーションとサニタイズの違いをはっきりと認識していなかったのが問題だったみたいですね。 それぞれの責任範囲をしっかりと割り振ることが大事なのかなー、と思いました。 共有いただいたURL先の記事も大変勉強になりました。 直接の解決策として提示いただいた他の方の回答をベストアンサーにさせていただきましたが(申し訳ありません…)、大変勉強になりました。 ありがとうございました!
tanat

2015/11/10 07:39

ベストアンサーのご判断は正しいものだと思います。お気になさらないでください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問