🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

Q&A

1回答

10686閲覧

LaravelのDB::rawでプレースホルダーを使用したい

hinata_t

総合スコア8

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

0グッド

0クリップ

投稿2019/12/10 13:58

編集2019/12/11 04:31

はじめに

Laravelでユーザー登録画面を作成しています。

ログインIDをテーブルに登録する際にAES_ENCRYPTで暗号化したいので、以下のように実装してみました。

  • /app/Http/Controllers/UserController.php

PHP

1// ~省略~ 2 public function store(CreateUserRequest $request) { 3 $user = new User; 4 5 $user->setLoginIdAttribute($request->login_id); // 暗号化 6 // ~省略~ 7 8 $user->save(); 9 10 return view('user.complete'); 11 } 12// ~省略~
  • /app/Models/User.php

PHP

1// ~省略~ 2use Illuminate\Database\Eloquent\Builder; 3use Illuminate\Support\Facades\DB; 4 5class User extends Model { 6 // ~省略~ 7 public function setLoginIdAttribute($value) { 8 $encryption_key = ENCRYPTION_KEY; // 定数 9 10 // TODO: この方法ではSQLインジェクションの心配があるため、対策を考えたい。 11 $this->attributes['login_id'] = DB::raw("HEX(AES_ENCRYPT('" . $value . "', '" . $encryption_key . "'))"); 12 } 13}

質問

この方法だとSQLインジェクションの心配が出てくると考えました。
$valueの値がエスケープされずに直接入れているため。

そのため、プレースホルダーを用いてエスケープしたいのですが、
DB:raw()でプレースホルダーを使用する方法はありますでしょうか?

もしくは、DB::raw()を使用しない もっといい方法がないでしょうか?

もしかすると初歩的な質問なのかもしれませんが、ご教示ください。

動かしている環境

  • Laravel:6.5
  • PHP:7.3
  • MySQL:8.0

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

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

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

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

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

m.ts10806

2019/12/10 20:26

>ログインIDをテーブルに登録する際にAES_ENCRYPTで暗号化してほしいとのこと どこからの依頼でしょうか。 >SQLインジェクションの心配が出てくると考えました 心配はいいとして、実際に試してみましたか?
hinata_t

2019/12/11 00:50

>どこからの依頼でしょうか。 この情報が必要な理由をお聞きしてもよろしいでしょうか? ひとまず、この暗号化は行わなければならない前提で回答を考えていただけますと幸いです。 >心配はいいとして、実際に試してみましたか? 試してみましたが、構文エラーでできませんでした。 ※私のやり方が間違っている可能性もありますが。 ちなみに$valueの値が以下になるようにやってみました。 `','')),~INSERT文のSQLが成り立つように記載~); DELETE FROM [テーブル名] WHERE id = [存在するID]; --`
m.ts10806

2019/12/11 01:03

>この情報が必要な理由をお聞きしてもよろしいでしょうか? もし業務関係である場合、質問サイトを頼って解決することは質問ではなく作業依頼となるからです。 本来、報酬が発生するものを無料で片付けようという魂胆があるのでしたら誰も助けようとはしません。
hinata_t

2019/12/11 01:36

なるほど、確かにそうですね。 質問に至った経緯としましては、以下です。 1. 仕事で似たような依頼を受ける 2. この問題に直面して、結局「はじめに」で書いた方法を諦める 3. (ここからプライベート)この問題を解決する方法はなかったのかと調べ始める 4. 質問する ただし、ここで知識を得てそれを今後仕事で使用しないとは限りませんので、 この質問は削除します。
m.ts10806

2019/12/11 01:39

得た知識技術を使うことに問題はないと思います。それがダメだと検索すらしてはダメということになります。 あくまで作業依頼のような形になっているとマズいというだけです。表現調整すれば良いと思います。
hinata_t

2019/12/11 04:31

>あくまで作業依頼のような形になっているとマズいというだけです。表現調整すれば良いと思います。 かしこまりました。表現を変更してみました。
退会済みユーザー

退会済みユーザー

2019/12/11 06:14

提示のコードではSQLインジェクションは発生しませんが、なぜそう思ったのでしょう?
hinata_t

2019/12/11 14:58

>提示のコードではSQLインジェクションは発生しませんが、なぜそう思ったのでしょう? プレースホルダーを用いずにエスケープされていない`$value`をSQLに直接組み込んでいるため、 `$value`の値の内容によってはSQLインジェクションが起きると考えました。 SQLインジェクションが発生しないとのことですが、根拠(「実はLaravelでは〇〇の部分で既にエスケープされている」など)があればご教示いただくことは可能でしょうか?
退会済みユーザー

退会済みユーザー

2019/12/11 15:06

$user->save(); でプレースホルダーを使う処理がなされます
hinata_t

2019/12/11 23:02

つまり、以下であった場合、 ``` $user = new User; $user->name = 'hoge' $user->save(); ``` SQL文は`INSERT INTO users (name) VALUES (?);`になるということでしょうか? そうなりますと、上の例であれば、`INSERT INTO users (login_id) VALUES (?);`になるということでしょうか?
退会済みユーザー

退会済みユーザー

2019/12/12 01:28

そういうことです。 ただコードを見る限り、要件を満たしていないと思われます。
mikkame

2019/12/12 05:16

kawaxさんの回答にもコメントしましたが ユーザーIDを暗号化すると、ログイン処理時にどのレコードが該当ユーザかわからなくなるため 全レコードを1個ずつ復元して対応していかないといけない気がします。 ユーザー数が多くなるにつれてログイン時間が肥大化していきます
hinata_t

2019/12/12 14:13

>そういうことです。 そうなると、login_idカラムは`HEX(AES_ENCRYPT('HOGE'', 'FUGA'))`という文字列が登録されると思いますが、実際に実行したところ暗号化された文字列がテーブルに登録されていました。 これは、プレースホルダーを用いてもエスケープされていないということでしょうか? >ただコードを見る限り、要件を満たしていないと思われます。 すみません、要件について詳しくご教示いただけますでしょうか?
退会済みユーザー

退会済みユーザー

2019/12/12 14:27

> 実際に実行したところ暗号化された文字列がテーブルに登録されていました。 これは、プレースホルダーを用いてもエスケープされていないということでしょうか? 言葉で言われても、多くの質問者が事実を述べているかは回答者に伝わりません(質問者、または回答者が事実誤認をしていたり、間違って覚えていたりする)ので、エビデンスを示してくれませんか?
hinata_t

2019/12/12 14:45

>言葉で言われても、多くの質問者が事実を述べているかは回答者に伝わりません(質問者、または回答者が事実誤認をしていたり、間違って覚えていたりする)ので、エビデンスを示してくれませんか? かしこまりました。 今、手元に動かせる環境がないので、後日とさせてください。 エビデンス(共有すべき情報)としては、 `$request->login_id`に入っている(入れた)値、実際にテーブルに格納された値の2つがあればよろしいでしょうか。 他にあったほうがよい情報などございますでしょうか?
hinata_t

2019/12/12 15:28

mikkameさん ご回答ありがとうございます。 >ユーザーIDを暗号化すると、ログイン処理時にどのレコードが該当ユーザかわからなくなるため >全レコードを1個ずつ復元して対応していかないといけない気がします。 >ユーザー数が多くなるにつれてログイン時間が肥大化していきます まったくもってその通りだと思います。 この方法で暗号化を行う必要がないこと や 暗号化することによってのデメリットがあることは理解できました。
退会済みユーザー

退会済みユーザー

2019/12/14 06:02

> `$request->login_id`に入っている(入れた)値、実際にテーブルに格納された値の2つがあればよろしいでしょうか。 そうですね。その結果追加で提示してもらいたいものが出てくるかもしれませんが、よろしくお願いします。
hinata_t

2019/12/16 14:38 編集

Kosuke_Shibuyaさん 入力した値、encryption_key、結果はそれぞれ以下となります。 login_id:loginidtest encryption_key:encryptionkey 結果:06AED6A088C61619BCCCC0EBDBA86AA3 また、以下のようなSQLを実行したところ、挿入された値の結果は同じものとなりました。 ``` INSERT INTO users (login_id, password) VALUES (HEX(AES_ENCRYPT('loginidtest', 'encryptionkey'), 'password'); ``` 結果:06AED6A088C61619BCCCC0EBDBA86AA3 上記の結果から、エスケープされていないと考えました。
guest

回答1

0

DB:raw()ではできないので代わりにselectRaw()など。
https://readouble.com/laravel/6.x/ja/queries.html#raw-expressions

そもそも1。DBで暗号化せずencrypt()使えばいい。

Laravelに組み込まれている暗号化機能を使用し、「自前」の暗号化アルゴリズムに走らないことを強くおすすめします。

https://readouble.com/laravel/6.x/ja/encryption.html

そもそも2。暗号化がいらない。
何のための暗号化?
上から言われたからってそのまま実装する初心者ではセキュリティ的には逆に危険。
「ユーザーIDも暗号化すべき」ならLaravelなら最初から暗号化するように作られてる。
でも違うので普通は暗号化は不要。
絶対暗号化は必要なんて言われるプロジェクトをLaravelで作るわけないのでやはり不要。

投稿2019/12/11 01:16

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

mikkame

2019/12/12 05:15 編集

ユーザーIDを暗号化したら全行総当たりする必要ありますよね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問