- 前回の勉強内容
- 今回の勉強内容 : SQLインジェクションの対策を学ぶ
- SQLインジェクションとは、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のことです。
- 入力値で仕込んでデータが再利用されたときに効力を発揮するセカンドオーダーSQLインジェクション
- シングルクオーテーションを使わないSQLインジェクション
- マルチバイト文字の問題
- 次回の勉強内容
前回の勉強内容
今回の勉強内容 : SQLインジェクションの対策を学ぶ
勉強のきっかけになった問題
SQLインジェクション対策について,Webアプリケーションの実装における対策とWebアプリケーションの実装以外の対策として,ともに適切なものはどれか。
情報セキュリティスペシャリスト 平成28年秋期 午前Ⅱ 問17
SQLインジェクションとは、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のことです。
【2】SQLインジェクションによる顧客情報流出 ― 不正アクセスの横綱!| Webサイトセキュリティ対策入門 by WAF「Scutum」プロジェクト
対策 : SQLを埋め込むところで特殊文字を適切にエスケープ
' → ''
\ → \\
今夜分かるSQLインジェクション対策:Security&Trust ウォッチ(42) - @IT
入力値で仕込んでデータが再利用されたときに効力を発揮するセカンドオーダーSQLインジェクション
たとえアプリケーションが常にシングルクオートをエスケープしていても、 攻撃者はなおも、データベース中のデータがそのアプリケーションで再利用さ れるときにSQLをインジェクトすることができます。
- 例えば・・・
- 攻撃者がアプリケーションに登録して、ユーザ名「admin'--」、 パスワード「password」のユーザ名を作る
- アプリケーションはシングルクオートを正しくエスケープして、INSERT文が作られる
- insert into users values ( 123, 'admin''--', 'password', 0xffff)
- 攻撃者がパスワードを変更する
- update users set password = '" + newpassword + "’ where username = '" + rso ( "admin'--") + "'"
- 最初にせっかくエスケープしたのに次には・・・・されず・・・クエリが生成される
- update users set password = 'password' where username = 'admin'--'
- 攻撃者は、admin'-- というユーザを登録することによって、admin のパスワードを自由にセットできる
対策 : データベースでのアクセス権は最小限に留める
不正なSQLがWebアプリから送られても最小限のアクセス権だけを与えることで被害を軽減できます。
シングルクオーテーションを使わないSQLインジェクション
SQLインジェクション対策というと、「'」の扱いばかりが注目されるが、「'」を使わなくても成立する攻撃もあります。
- 例えば・・・
- SELECT name FROM user where uid = '$uid' AND age > $age
- 渡される$uidと$ageの特殊文字は、適切にエスケープ!が、こんなものがきたら・・・
- $uid:ueno
- $age:31 UNION…
- SELECT name FROM user where uid = ' ueno ' AND age > 31 UNION……
- UNION以降のSQLも実行されてしまう・・・
- 対策 : 問題は、ageの値をシングルクオーテーションで囲う
- SELECT name FROM user where uid = '$uid' AND age > '$age'
対策 : SQLのプレースホルダを利用する
プレースホルダとは、ユーザ入力をもとに生成される部分に特殊文字を使用したSQL文中のひな形を用意し、その変数部分には実行時に値を割り当てる仕組みです。
PHPの場合 : $1と$2がプレースホルダ
PHPでのSQLインジェクション対策 - プレースホルダ編 | Let's Postgres$res = pg_query_params( $dbconn, 'UPDATE users SET profile = $1 WHERE userid = $2', array($_REQUEST['profile'], $_SESSION['me']['userid']) );
Javaの場合 : ?がプレースホルダ
安全なSQLの呼び出し方 - QiitaPreparedStatement prep = conn.prepareStatement("SELECT * FROM employee WHERE name=?"); prep.setString(1, "山田");
マルチバイト文字の問題
- 例えば・・・入力値「\x97' OR A=A」をエスケープ処理すると「予' OR A=A」になる