2023.10.05
Laravelは、PHPで不動の人気を誇るフレームワークです。Web開発に必要な機能がたっぷり盛り込まれ、手軽にリッチなアプリケーションを開発することができます。
もちろん、セキュリティもばっちりで、基本的な脆弱性はLaravelが事前に対策してくれています。
Laravelでデータベースの操作を行う際には、Eloquentやクエリビルダを使います。例えば、usersテーブルからデータを取得するには、以下のようなコードを書きます。
// Eloquent
$user = User::where('username', '=', 'transonic')->first();
// クエリビルダ
$user = DB::table('users')->where('username', '=', 'transonic')->first();
MySQLのログを確認したところ、以下のようなクエリが発行されていました。
23 Prepare select * from `users` where `email` = ? limit 1
23 Execute select * from `users` where `email` = 'transonic' limit 1
23 Close stmt
23 Prepare select * from `users` where `email` = ? limit 1
23 Execute select * from `users` where `email` = 'transonic' limit 1
23 Close stmt
どちらも同じクエリになっていますが、注目すべきは 「?」です。これは、プレースホルダーと呼ばれるもので、SQLインジェクションの対策として使用されています。
開発者が特に意識しなくても、セキュリティ対策をしてくれているので、うっかり脆弱性を作りこんでしまう心配がありません。
いくら対策されているとはいえ、何をやってもいいわけではありません。場合によっては、LaravelでもSQLインジェクションが発生してしまいます。
例えば、以下のようにRawがつくメソッドを使うと、SQLインジェクションにつながる可能性があります。
$search = $request->get('search');
$user = DB::table('users')->whereRaw("email = '{$search}'")->where('deleted_at', '=', null)->get();
ここで、$user_inputに「’ OR 1=1 — – 」と入力されると、検索条件に関わらずusersテーブルの全行が取得されてしまいます。
64 Prepare select * from `users` where email = '' OR 1=1 -- -' and `deleted_at` is null
64 Execute select * from `users` where email = '' OR 1=1 -- -' and `deleted_at` is null
64 Close stmt
Rawメソッドは他にもいくつかあります。
など…
詳しくはドキュメントを参考にしてください。
statementメソッドはSQLクエリを直接発行できる機能で、こちらもRawメソッドと同様な危険性をはらんでいます。
$search = $request->get('search');
$user = DB::statement("SELECT * FROM mt_users WHERE email = '{$search}'");
Rawの場合と同じように任意のSQLクエリが実行できます。
109 Prepare SELECT * FROM users WHERE email = '' OR 1=1 -- -'
109 Execute SELECT * FROM users WHERE email = '' OR 1=1 -- -'
109 Close stmt
SQLインジェクションの脆弱性がある場合、どのような影響が発生するでしょうか?
アプリケーションの構成にもよりますが、以下のような攻撃につながるリスクがあります。
など…
アプリケーションがクラッシュするだけならいいですが、ユーザーの個人情報が流出したり、サーバーの乗っ取りにつながる可能性もあるので注意しなければいけません。
Laravelでは、基本的なSQLインジェクション対策がなされているので、Eloquentやクエリビルダを適切に使っている限りは特に対策は必要ありません。
ただし、Rawメソッドやstatementメソッドは不必要に使わないことをおすすめします。どうしても使用しなければならない場合は、必ずプレースホルダーを使ってバインディングしてください。
DB::table('users')->whereRaw("email = ?", [$select])->first();
以下のように、シングルクォーテーションがエスケープされています。
116 Prepare select * from `mt_users` where email = ? limit 1
116 Execute select * from `mt_users` where email = '\' OR 1=1 -- -' limit 1
Laravelには、便利な機能がたくさん用意されているので、あまり深く考えずどんどん使ってしまいますが、中身を理解していないと思わぬ落とし穴にハマってしまいます。セキュリティ対策の基本をしっかり押さえて、安全なアプリケーションを構築しましょう!
以上。