Jの衝動書き日記

さらりーまんSEの日記でございます。

体系的に学ぶ安全なWebアプリケーションの作り方の読書メモ 第4回 SQLインジェクションまとめ

今回はセキュリティ関係のトラブルでよく目にするSQLインジェクションについてまとめてみた……つもりのメモである。

SQLインジェクションとは何か?

SQLインジェクションとは開発者の意図しない形にSQL文が改変されること。

よくある事例

  • ログイン回避
    • WHERE句を常に成功させるようにパスワードを入力→本来の条件を終わらせ、OR文で常に成功するような文を埋め込む(OR 1 = 1など)
  • データの改竄
    • 本来のSQL文を終わらせ、別のSQL文を埋め込む
      • ' ; update〜 '-- → --以降はコメント文として認識させる
  • union selectによる漏洩
    • 一度の攻撃で大量に情報が漏洩(出力結果に上手く合致するようにSQLを発行)
  • エラーメッセージ経由の漏洩
    • わざとエラーを発生させ、その出力内容から情報が漏洩する
      • ユーザ名とパスワードを取得し、それをint型にキャスト → エラーとなるが、ユーザ名とパスワードが表示される
  • ファイルの読み込み
    • データベースの拡張コマンドを使用させる
      • ファイルをあるテーブルにコピー → 参照 で漏洩

SQLインジェクションが発生する理由

リテラルの扱いが不十分のため。型に応じた表現形式が必要。

  • 文字列リテラル
    • シングルクォートで囲う
    • シングルクォート自体は、シングルクォートを重ねることでエスケープ
    • 脆弱性があるプログラムでは、このエスケープ処理をしていない
  • 数字リテラル
    • 変数に数字以外の文字列を入れたり出来る → スクリプト系の言語
  • 根本的な原因
    • パラメータとして指定した文字列の一部がリテラルをはみ出すことにより、 SQL文が変更されること

対策

自前でパラメータの値を含めてSQL文を作成するな!が基本。置き換えはデータベースにまかせてしまおう。

  • プレースホルダによる置き換え → Prepared Statementとも言う
  • SELECT * FROM books WHERE author = ? ORDER BY id 
    • ?がプレースホルダ
    • ?の置き換えはデータベース上で行われる
      1. ?が付いたSQL文をデータベースへ送信
      2. データベースがSQL文をコンパイル
      3. ?に割り当てる変数を送信
      4. データベースがコンパイル済のSQLに変数を割り当てる(バインドする)
    • SQLもキャッシュされるので効率も良くなる
  • ソートの列名
    • 列名を外部から入力指定可能とすると脆弱性が発生する
    • 決められたものしか入らないようにチェック処理を入れる必要がある
  • 保険的な対策
    • 詳細なエラーメッセージの抑止
    • 入力値の妥当性検証
    • データベースの権限設定
  • Javaの場合
    • SQL文を組み立ててStatementを作成→駄目
    • PreparedStatementを使ってパラメータ設定が正解
    • O-Rマッパーを使っている場合は大抵これのはずなので問題ない
    • javaで静的プレースホルダを使用する方法(MySQLの場合)
      • DriverManager.getConnection時にuseServerPrepStmts=trueを指定
    • Oracleは特に指定しなくても使用する

参考文献

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践