はじめに
こんにちは。小川です。
以前から気になっていた「SQLアンチパターン」という本を読みました。
とても良い本で今まで気づかずにやっていたことがSQLアンチパターンなんだと知ることができました。
勉強になったので、学んだことを言語化して量が多いのでいくつかの記事に分けて紹介していこうと思います。
今回は第Ⅳ部のアプリケーション開発のアンチパターンについて記載します。
この記事は「SQLアンチパターン」の気づき(アプリケーション開発1)の続きになります。
20章.SQLインジェクション
SQLインジェクションとは
多くの場合、SQLはアプリケーションコードと連携して使われます。
SQLクエリを文字列として作成し、文字列内にアプリケーション変数を挿入する方法を動的SQLと呼びます。
SQLインジェクションとは、動的SQLの変数に悪意のある文字列を埋め込むことで、実際の使い方と異なる意図しない挙動をさせることです。
アンチパターン:未検証の入力をコードとして実行する
SQLインジェクションの典型例は、挿入された値によって、元のSQL文の実行に続けて別のSQL文も実行されるというものです。
例
-- $bugIdは変数
SELECT * FROM Bugs WHERE bug_id = $bugId
-- 変数$bugIdに123;DELETE FROM Bugsをセットする
SELECT * FROM Bugs WHERE bug_id = 123;DELETE FROM Bugs
このSQLではデータを取得していただけなのに、データが全て削除されてしまいます。
これは開発者の意図しない結果になっています。
デメリット
SQLが不当に実行されることにより、データの削除、更新、取得など開発者が意図しない挙動をします。
ユーザIDとパスワードが盗まれてしまうことや、大事な顧客データが削除されたり、個人情報の流出など引き起こされる可能性があります。
解決策:誰も信用してはならない
SQLコードの安全性を保障するための唯一の方法などというものは存在しません。
そのため以下の技法習得し、状況に応じて適切に使い分けるようにしましょう。
-
入力のフィルタリング
ユーザからの入力に危険な文字列が含まれていないかどうかを探るよりも、その入力にとって無効な文字を初めからすべて取り除くようにすべきです。
正規表現を用いて安全な文字列を判別し、無効な内容をフィルタリングする方法もあります。 -
動的値のパラメータ化
動的な部分がシンプルであるならSQLから分離させるためにプリペアドステートメントを使用できます。
SQLから分離するとは、例えば変数に悪意のある文字列が渡ってきたとします。例 SELECT * FROM Bugs WHERE bug_id = ? -- 入力値を全て文字列として置き換えることで悪意のあるSQLをそのまま実行しないようにする SELECT * FROM Bugs WHERE bug_id = '123;DELETE FROM Bugs'
-
ユーザの入力をコードから隔離する
エスケープやプリペアドステートメントはほとんどの場合に有効ですが、テーブル識別子、列識別子、SQL予約語には適用できません。
そういった場合はユーザの入力を直接SQLの変数に置き換えるのではなく、コードで制御する必要がある
まとめ
今回は第Ⅳ部のアプリケーション開発のアンチパターンについて一部まとめてみました。
この記事はこの本を読んで、私がこういう理解をしましたということを言語化してみました。
とても勉強になる本なので皆様もぜひ読んでみてください。
以上、小川でした。