徳丸本読書会sql csrf
TRANSCRIPT
SQLインジェクション & CSRF 原理とその対策(for Perl) 徳丸本勉強会 2013.11.17 @addsict
github.com/addsict/TokumarubonDokusyokai
hIps://github.com/addsict/TokumarubonDokusyokai
github.com/addsict/TokumarubonDokusyokai
SQLインジェクション
github.com/addsict/TokumarubonDokusyokai
SQLインジェクションとは
• Webサイトの脆弱性攻撃の定番中の定番 • SQL文の構文を「破壊」し悪意のあるSQLに変
え, テーブルの削除やパスワードの漏洩などを導く攻撃
• 今日は文字列連結ではない安全なSQLの組み立て方を見ていく – あまり深堀りはしません…
github.com/addsict/TokumarubonDokusyokai
どんな風にSQL文が壊されるの?
• WebアプリケーションなどではSQL文のリテラル部分がパラメータされていることが一般的 – リテラル: 文字列リテラル, 数値リテラルなど
• パラメータに含めた変数が展開されると, 意図しないSQLに変わる危険性 – リテラル以外のものが注入される
github.com/addsict/TokumarubonDokusyokai
my $sql = “SELECT * FROM users WHERE userid=‘$userid’”;
“SELECT * FROM users WHERE userid=‘’; DELETE FROM users;-‐-‐’”; # -‐-‐ 以降はコメントアウト
$userid = “’;DELETE FROM users;-‐-‐”; を注入 ⇒
Exercise: SQLインジェクション
• SQLインジェクションを実際にやってみましょう – レポジトリのsql-‐injec`on/ 内のREADME参照
• 補足 – DBD::mysqlの場合, 複数SQL文を一度に実行するmysql_mul(_statementsがデフォルトではoffなので, DBI-‐>connect時にonにしてある
github.com/addsict/TokumarubonDokusyokai
SQLインジェクション対策
• プレースホルダを使用するのが一番安全 – 静的プレースホルダ – 動的プレースホルダ
github.com/addsict/TokumarubonDokusyokai
静的プレースホルダとは?
• SQLの実行方法に基づいた安全なSQLの組み立て方 – SQLの実行の流れ: SQLパース ⇒ 構文解析 ⇒ … ⇒ 実行
• 値が未定のパラメータを含んだSQLを構文解析まで済ませておき, 後にパラメータをバインド – 構文解析が完了したことでバインド値によらず構文が「破壊」されるこ
とはない ⇒ 原理的に安全 – DBIではprepareで構文解析を行い, bind_paramでパラメータをバイン
ドし, executeで実行 • *execute時にパラメータをバインドできるが, パラメータ値が常にVARCHAR型
とみなされSQLの実行時に文字列型から実際の型への変換が行われる • Prepared Statementと呼ばれる
github.com/addsict/TokumarubonDokusyokai
my $sth = $dbh-‐>pepare(“SELECT * FROM users WHERE userid = ?”); # ?がプレースホルダ $sth-‐>bind_param(1, “addsict”, SQL_VARCHAR); # パラメータをバインド $sth-‐>execute();
動的プレースホルダはどう違うの?
• やっていることは文字列連結と変わりない – アプリケーション側で文字列連結するのではなく,
ライブラリ・ドライバ側で文字列連結を行う – DBに応じて適切なエスケープ処理やリテラルの
型をチェックし安全性を担保
• DBD::mysqlの場合動的プレースホルダがデフォルトの挙動 – 静的プレースホルダを使うにはDBI-‐>connectでmysql_server_prepareオプションをONにする
github.com/addsict/TokumarubonDokusyokai
ORM内でのSQLの組み立て方
• 普段使用しているORMが実際にどのようにSQLを組み立てているか見てみましょう – プレースホルダは使われていますか?
• Tengの場合 – SQL生成はSQL::Makerという別のモジュール – SQL::Maker::_make_where_condi`on ⇒ SQL::Maker::Condi`on::add ⇒ SQL::Maker::Condi`on::_make_tern
github.com/addsict/TokumarubonDokusyokai
Exercise: SQLインジェクション対策
• 先ほどの脆弱性を含むサイトを, SQLインジェクション対策するように改変してください
github.com/addsict/TokumarubonDokusyokai
合わせて読みたい
• 「安全なSQLの呼び出し方」 IPA – hIp://www.ipa.go.jp/files/000017320.pdf
• 「SQLインジェクションゴルフ」 徳丸浩の日記 – hIp://blog.tokumaru.org/2013/06/sql-‐injec`on-‐golf.html
• 「mysql の server side prepared statement って速いの?」 tokuhirom’s blog – hIp://blog.64p.org/entry/20080807/1218080835
github.com/addsict/TokumarubonDokusyokai
CSRF
github.com/addsict/TokumarubonDokusyokai
CSRFの概要
• Cross Site Request Forgeriesの略 – Forgeryって? → (文書などの)偽造の意
• Webアプリケーションの「重要な処理」を行うリクエストを偽装して実行する(なりすまし)攻撃 – 重要な処理: パスワード変更, ブログ投稿など
冪等性を持たない処理 • できることはWebアプリにHTTPリクエストを送るだけな
ので, サーバサイドのロジックのみ悪用できる – この点でXSSとは異なる
• 有名な事例 – mixiのはまちちゃん事件
github.com/addsict/TokumarubonDokusyokai
CSRF攻撃成立までの流れ
• ユーザがターゲットサイトAにログインする • ユーザが悪質なサイトBにアクセスする – サイトBでは(非表示に設定された)iframe内で攻
撃用ページB’にアクセスする • iframeを使うのはユーザに攻撃がばれないようにする
ため
– ページB’ではサイトAの「重要な処理」を行うリクエストを発行することで攻撃完了
github.com/addsict/TokumarubonDokusyokai
この2つの条件が満たされただけで攻撃されてしまう!!
Exercise: CSRF
• CSRF攻撃を体験してみましょう – レポジトリのcsrf/ 内のREADME参照
github.com/addsict/TokumarubonDokusyokai
CSRF攻撃が生まれる原因
• ブラウザ(の仕様)が悪い! – form要素のac`on属性にどのドメインのURLでも指定
可能 • 同一生成元ポリシーは適用されない
– クッキーは自動的にリクエスト先のサイトに送信される • ログイン済みであればセッション情報がクッキー上に
• 正規リクエストと偽造リクエストの違いはRefererの違いだけ – ログを見てリクエストヘッダを確認してみよう
github.com/addsict/TokumarubonDokusyokai
CSRFの対策は?
• まずCSRF対策が必要なページを区別 – 全てのページにCSRF対策が必要なわけではない
• CSRF対策されると困るケースもある(他のサイトからのリクエストが重要なページなど)
• 対策手法 – Refererをチェックする – 第三者が知りえないトークンを埋め込む
github.com/addsict/TokumarubonDokusyokai
対策手法 -‐ Refererのチェック -‐
• 正規リクエストと偽造リクエストはRefererが異なる – render_403 if header-‐>{referer} ne proper_referer;
• 注意点 – Refererを送信しないように設定する利用者もいる – Refererチェックの漏れが起こりうる
• hIp://tokumaru.jp/ からのリクエストを許す場合以下の正規表現で大丈夫? xxxxにURLを入れて試してみよう
github.com/addsict/TokumarubonDokusyokai
perl -‐e ”$referer = xxxx; if ($referer =~ m#^hIp://tokumaru.jp#) {print 'ok';}"
対策手法 -‐ トークンの埋め込み -‐
• 攻撃者が事前に知りえない情報をリクエストに含めて渡す – POSTの場合, リクエストbodyにトークンを含める – トークンとしてセッションIDを使うのが簡易な方法
• <input type=“hidden” name=“token” value=“<: $sid :>”> • CSRFではターゲットサイトのCookieには触れないことに注意
• twiIerもこの対策を取っている – Chromeの開発者ツールを開いた状態でツイートしてみよう.
ツイート内容と共に何がPOSTされてますか? • 実装めんどい?
– それCPANにあるよ Plack::Middleware::CSRFBlock • POSTメソッドを使用するformタグを探し, トークンを自動で埋め込む • 既存アプリのコードに手を入れないでok
github.com/addsict/TokumarubonDokusyokai
Exercise: CSRF対策
• 先ほどの脆弱性を含むサイトを, CSRF対策するように改変してください – Refererチェックで対策する例
• csrf/refererブランチ
– トークンで対策する例 • csrf/tokenブランチ
github.com/addsict/TokumarubonDokusyokai