hirapi's blog

ちゃんとしたふりをする

IPAが公開する「安全なウェブサイトの作り方」第1章「ウェブアプリケーションのセキュリティ実装」を読んだ

www.ipa.go.jp

徳丸本の中の御方も編集に加わられているとのこと。
構成は

  • 第1章「ウェブアプリケーションのセキュリティ実装」
  • 第2章「ウェブサイトの安全性向上のための取り組み」
  • 第3章「失敗例」

このうち第1章を読んだので、要点とか気になったとことか別の参考サイトとかのメモを残す。

1.1 SQL インジェクション

  • 外部から入力された値を直接SQL文に組み込むような実装で、任意のSQLを発行されてしまう
  • SELECT name FROM users WHERE id = (入力値)
    • 入力値が 1 OR 1 = 1;-- だった場合、 1 = 1 に全レコードがひっかかり、全ユーザの情報が閲覧できてしまう
    • -- で後ろの条件がコメントアウトされる)

対策

  • SQLプレースホルダの機構を使ってSQL文を組み立てる
  • データベースエンジンのAPIを使ってリテラル内の特殊文字エスケープする
  • エラーメッセージを直接返さない
    • インジェクションされても、せめて情報を見られないようにする
  • データベースのアクセス権限を制限する
    • 不必要なUPDATEやDELETEの権限をつけない

1.2 OS コマンド・インジェクション

  • 外部入力を元にコマンドを実行するような実装で、悪意あるコマンドを実行されてしまう

対策

  • 外部コマンドを実行するような言語機能を使わない
  • やむなく使う場合は引数に渡せる値をホワイトリスト制にする

1.3 パス名パラメータの未チェック/ディレクトリ・トラバーサル

  • 外部からの値(URLのパラメータ等)を使ってファイルを指定するような実装で、意図しないファイルパスが指定され、意図しない処理をしてしまう
    • 機密情報の書かれたファイルの中身を返してしまうとか
    • そういえば昔phpmyadminの何かのファイルを探すような攻撃を受けて404が鳴り響いたことがある

対策

  • 外部からの値をファイル指定に使わない
  • 指定可能なディレクトリを限定し、かつ入力値のうち末尾のファイル名だけを使う
    • ディレクトリを指定したつもりでも、入力値に ../ などが入っていると別のディレクトリに行ってしまう
    • PHPでいう basename() などの関数でファイル名だけを取り出して使う
  • サーバ内でアプリケーションのアクセスできるファイルを限定する
  • ファイル名にディレクトリの区切り文字が入っていないか確認する

1.4 セッション管理の不備

  • セッション・ハイジャック
  • セッションIDによるログイン管理を行なっている場合になりすまされる
  • セッションIDの推測
    • IDの生成規則を推測して自分でセッションIDを入れ、他のユーザになりすます
  • セッションIDの盗用
    • 他のユーザのセッションIDを盗んでなりすます
  • セッションIDの固定化(Session Fixation)
    • 悪意あるユーザAが自分用のセッションIDを他のユーザBに送り込み、その状態で他のユーザが自身のアカウントでログインすると、送り込まれたIDがBのログインと紐付き、Aが同じセッションIDを入れた状態でサイトを訪れたときBのアカウントと認識される
  • ブラウザの脆弱性やアプリケーションのXSS脆弱性を突きcookieを読み書きすることで、セッションIDを盗んだり送り込んだりできる

対策

  • セッションIDはcookieか、hiddenでPOSTする
    • URLのパラメータに入れない(POSTでなくてもレスポンスヘッダのreferrerに出てくる)
    • フレームワークによってはcookie拒否の場合に自動でURLのパラメータにするものがあるので設定変更
  • HTTPS cookieにはsecure属性をつける、HTTP通信で使うcookieは区別して扱う
  • ログイン前にセッションIDを発行・利用する実装は避ける
    • もし必要な場合は、ログイン後に、ログイン前に発行したセッションIDは無効化する
  • cookieの有効期限を短く設定する
    • ブラウザを閉じずに使い続ける可能性も考慮

1.5 クロスサイト・スクリプティング

  • サイトの閲覧者が自分でjsを実行するわけではない
  • サイトを開くとjsが実行されるようなリンクを悪いやつが用意し、それを無垢な人がクリックする
    • サイトのドメインcookieの内容が外部に送られる
    • サイトのドメインcookieが書き込まれる(→ セッションの固定化に使われたり)
    • サイト上に本来のコンテンツと違うものが表示される
  • 前提知識:
    • 埋め込まれるjsはHTMLタグのかたちをしている(そりゃそう)

      • <script src="evil.js"></script>
      • <script>alert('evil-content');</script>
    • URLのスキーマjavascript: という形式がある

      • javascript:alert('evil-content'); というURLのリンクを開くと、もともと表示していたサイトでjsを実行したことになる f:id:chmv:20200702183521p:plain
    • IEの独自拡張で、CSSでjsを実行できる: expression()
  • ユーザの入力を表示に反映させる機能に注意
    • 確認画面・フォームのエラー表示
    • 検索結果
    • コメント

対策

  • HTTPレスポンスヘッダのContent-Typeでcharsetを指定する
    • 指定しないと、先頭の文字でブラウザが勝手に解釈する
    • 例:UTF-7で解釈されるとscriptタグになる文字列を埋め込まれる ⚠️
      • サーバ側でUTF-8EUC-JP等で解釈してエスケープをしてもHTMLタグ等が見逃される。ブラウザがUTF-7として解釈するように仕向けられるとブラウザでスクリプトが実行される
      • サーバ側でUTF-7としてエスケープしても、他の文字コードでやられるし、本来表示したかったものが表示できない
  • cookieにHttpOnly属性をつけるXSS脆弱性を無くすものではない)
    • スクリプトから読み書きできなくなり、cookieの盗用・固定化を防ぐ
    • ブラウザによっては対応してないかも
    • あわせてTRACEメソッドを無効化する
      • Windows XP以前
      • XSS脆弱性を突かれたときリクエストヘッダが全て読み取られる
        • Cross-Site tracing
        • ヘッダにはHttpOnly cookieを含め全部書かれている
  • XSS対策用のブラウザの設定を有効にするレスポンスヘッダを付ける

  • HTML形式の入力を許可しないサイト:

    • HTMLタグをエスケープ:てかサイト上に表示する全部の文字をエスケープ
      • ユーザからの入力や、データベース・ファイルから取得した文字の表示 というか全部エスケープしたほうが安心
      • jsで動的にページを表示するときにわたす内容
    • URLのスキーマhttps://http:// に限定
    • scriptタグ内のスクリプトを動的に生成しない(ユーザの入力を反映させない)
    • 任意のCSSのファイルを読み込まない
  • HTML形式の入力を許可するサイト:掲示板とか?
    • 構文解析をしてスクリプト実行につながる要素をまるごと取り除く(むずそう)
    • 保険的対策:やばそうな文字列を置換する
      • 文字列だけ部分的に削除した結果それはそれでスクリプト実行につながる可能性がある javajavascriptscript: とか?
      • むずそう↓

        ウェブブラウザによっては、「java script:」や「java(改行コード)script:」等の文字列を「javascript:」と解釈してしまう

1.6 CSRF(クロスサイト・リクエスト・フォージェリ)

  • forgery:偽造・捏造
  • ユーザの意図していないリクエストを送る
    • サイト外の罠から、サイトに向けてリクエストが送られる
    • 例:給付金振り込み口座を変更する操作(← 本来の給付金サイト内で実行されるリクエストを調べればわかる)を実行するリンクを貼った罠サイトを用意し、給付金サイトにログイン済みのユーザにリンクを踏ませる
  • 対象:
  • サーバへのリクエストが自分のサイトから送られたものであることを確認するべし
  • CORSポリシーにより別ドメインからのリクエストに対してレスポンスは返さないが、データベースの操作等の副作用は起こる

対策

  • ここも参考 これで完璧!今さら振り返る CSRF 対策と同一オリジンポリシーの基礎 - Qiita
  • hiddenパラメータにトークンを入れ、サーバ側で照合する
    • firebaseでやってたやつ。Railsもフォーム中で勝手にやってくれる
    • POSTにすること(当然では)
      • GETにすると、外部サイトに遷移したときrefererで見れるため
      • RFCでも「機密性の求められるデータの送信にはPOST」と書いてあるらしい
  • 実行する直前で再度パスワードの入力を求める
  • Refererが空でなく、かつ正しいリンク元か確認する
    • ※ 自分のサイト内に罠を設置されると駄目
    • ※ ブラウザ等の設定でReferer送らないユーザが使えなくなる
  • 重要な操作時、ユーザにメールで通知する
    • メール本文に機密情報を入れないこと

1.7 HTTP ヘッダ・インジェクション

対策

  • ヘッダの出力を、言語やフレームワークAPIで行う
    • ちゃんと対策してくれてるはずなので
  • APIが無ければ、ヘッダの値に改行が含まれないよう処理する
    • 改行以降の文字を削除するとか
    • 改行コードを削除するとか
    • LocationにURLを入れる場合はURLエンコーディング

1.8 メールヘッダ・インジェクション

  • 参考: メールヘッダ・インジェクションとは | 分かりやすく図解で解説
  • HTTPヘッダ・インジェクションとだいたい同じ
  • フォームからの問い合わせを管理者にメールで通知するなど、ユーザの入力内容をメールで送信する機能にありがち
  • メールヘッダ中の値(Subject, To, Fromなど)をユーザからの入力で動的に変えている場合、ユーザの入力に改行とヘッダ要素が含まれていると改ざんされる
  • 例:Subjectにユーザの入力テキストを入れる
    • 件名入力フォームに (改行コード)Bcc:メールアドレス を入れられると、Bccが追加される
    • Bccだと管理者も気づきにくい
    • メーリングリストのアドレスを指定される可能性もある

対策

  • ユーザからの入力をメールヘッダに入れず、全て本文に入れる
  • 送信処理を、メール送信用のAPIで行う
  • ヘッダの値に改行が含まれないようにする

1.9 クリックジャッキング

  • CSRFに似ている
  • 罠サイト上にiframeで元サイトを開き、透明にする
    • 見た目は罠サイトだが、要素は元サイト
    • 元サイトにログインした状態で罠サイトをクリックすると、元サイト上で操作したのと同じになる
    • (透明なのでフォーム等は使えず、元サイトの中のクリックで操作する機能に限られる)
  • 注意が必要な機能:
    • ユーザの個人情報の公開範囲を設定する部分

対策

  • レスポンスヘッダにX-Frame-Optionsを設定
    • frame・iframeでの読み込みを禁止する
    • IE7は対応していない
  • 実行する直前で再度パスワードの入力を求める
  • 重要な処理をマウスだけで完結させない

1.10 バッファオーバーフロー

  • 参考:
  • wikipediaよりざっくり:
    • 古典的バッファオーバーフロー
      • 確保されたバッファより大きいデータを入れてしまい、隣のデータが上書きされる
      • 隣に権限を示すフラグなどが入っていた場合、管理者権限が乗っ取られることになる
    • スタック型
      • スタック領域:コールスタックを格納する領域
        • コールスタック:スタックフレームを並べたもの
          • スタックフレーム:関数内の変数や実行後に戻る呼び出し元関数のポインタの情報
      • 関数のスタックフレーム内で確保していたローカル変数用の領域を超えるデータをその変数に入れてしまい、スタックフレーム内で近くに書かれているリターンアドレスが上書きされる
      • 悪意あるコードを同時に送りつけられ、リターンアドレスがそれを指すよう上書きされると、実行されてしまう
      • (どうやってうまいことリターンアドレス部分にデータを書き込むかについても書かれているけど難しすぎた)
    • ヒープ型
      • ヒープ領域: malloc などで動的に確保された、計算や操作に利用する領域
      • ヒープ領域を利用する(= 動的にメモリ確保を行う)関数を対象にする
      • 関数が2つのヒープ領域を確保しているとき、1つをオーバーフローさせることでもう1つの領域にデータを書き込む
    • 結果↓
      • クラッシュさせる
      • write-what-where状態(任意の場所に任意の値を書き込める状態)
      • 任意のコードを実行できる

対策

  • 直接メモリにアクセスできない言語を使う
  • ライブラリを最新のバージョンにして使う
  • 直接メモリにアクセスする必要がある場合は最小限に

1.11 アクセス制御や認可制御の欠落

  • 非公開の情報にアクセスするためにパスワードなど他人に知られない前提の情報を使う
  • 認証後、認可に必要な情報をログイン中のユーザ以外から見えないようにする
    • 注文番号で検索でき、かつ注文番号が取得・推測可能なものであれば、結果的に誰でも見えてしまう
    • 認可に使うキーとなる情報をGETやPOSTで渡すのもNG