IPAが公開する「安全なウェブサイトの作り方」第1章「ウェブアプリケーションのセキュリティ実装」を読んだ
徳丸本の中の御方も編集に加わられているとのこと。
構成は
- 第1章「ウェブアプリケーションのセキュリティ実装」
- 第2章「ウェブサイトの安全性向上のための取り組み」
- 第3章「失敗例」
このうち第1章を読んだので、要点とか気になったとことか別の参考サイトとかのメモを残す。
- 1.1 SQL インジェクション
- 1.2 OS コマンド・インジェクション
- 1.3 パス名パラメータの未チェック/ディレクトリ・トラバーサル
- 1.4 セッション管理の不備
- 1.5 クロスサイト・スクリプティング
- 1.6 CSRF(クロスサイト・リクエスト・フォージェリ)
- 1.7 HTTP ヘッダ・インジェクション
- 1.8 メールヘッダ・インジェクション
- 1.9 クリックジャッキング
- 1.10 バッファオーバーフロー
- 1.11 アクセス制御や認可制御の欠落
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が鳴り響いたことがある
対策
- 外部からの値をファイル指定に使わない
- 指定可能なディレクトリを限定し、かつ入力値のうち末尾のファイル名だけを使う
- サーバ内でアプリケーションのアクセスできるファイルを限定する
- ファイル名にディレクトリの区切り文字が入っていないか確認する
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する
- HTTPS cookieにはsecure属性をつける、HTTP通信で使うcookieは区別して扱う
- ログイン前にセッションIDを発行・利用する実装は避ける
- もし必要な場合は、ログイン後に、ログイン前に発行したセッションIDは無効化する
- cookieの有効期限を短く設定する
- ブラウザを閉じずに使い続ける可能性も考慮
1.5 クロスサイト・スクリプティング
- サイトの閲覧者が自分でjsを実行するわけではない
- サイトを開くとjsが実行されるようなリンクを悪いやつが用意し、それを無垢な人がクリックする
- 前提知識:
- ユーザの入力を表示に反映させる機能に注意
- 確認画面・フォームのエラー表示
- 検索結果
- コメント
対策
- HTTPレスポンスヘッダのContent-Typeでcharsetを指定する
- cookieにHttpOnly属性をつける(XSS脆弱性を無くすものではない)
XSS対策用のブラウザの設定を有効にするレスポンスヘッダを付ける
- ブラウザによって対応状況が異なる
X-XSS-Protection: 1; mode=block
Content-Security-Policy: reflected-xss block
HTML形式の入力を許可しないサイト:
- HTML形式の入力を許可するサイト:掲示板とか?
1.6 CSRF(クロスサイト・リクエスト・フォージェリ)
- forgery:偽造・捏造
- ユーザの意図していないリクエストを送る
- 対象:
- cookieをつかって認証している
- BASIC認証
- SSLクライアント認証
- サーバへのリクエストが自分のサイトから送られたものであることを確認するべし
- CORSポリシーにより別ドメインからのリクエストに対してレスポンスは返さないが、データベースの操作等の副作用は起こる
対策
- ここも参考 これで完璧!今さら振り返る CSRF 対策と同一オリジンポリシーの基礎 - Qiita
- hiddenパラメータにトークンを入れ、サーバ側で照合する
- firebaseでやってたやつ。Railsもフォーム中で勝手にやってくれる
- POSTにすること(当然では)
- 実行する直前で再度パスワードの入力を求める
- stripeのダッシュボードでやってるやつか
- Refererが空でなく、かつ正しいリンク元か確認する
- ※ 自分のサイト内に罠を設置されると駄目
- ※ ブラウザ等の設定でReferer送らないユーザが使えなくなる
- 重要な操作時、ユーザにメールで通知する
- メール本文に機密情報を入れないこと
1.7 HTTP ヘッダ・インジェクション
- 参考:
- 前提知識:
- レスポンスヘッダの要素間は改行で区切られている
- レスポンスのヘッダとボディは空白行で区切られている
- 例:URLのパラメータ(redirect_urlとか)を直接Locationに入れるような実装
- redirect_urlに改行文字
%0D%0A
とヘッダ形式の文字列Set-Cookie: id=foo
を入れられると、レスポンスヘッダにそのままSet-Cookie
要素が入ってしまい、ユーザのブラウザに任意のcookieが付与されてしまう - redirect_urlに空行(改行文字を続けて2つ)を入れられると、続く文字列がレスポンスボディになってしまい、任意のHTMLやjsをユーザに表示・実行させることができる
- 空行を続けた後に2つ目のまるごと偽のレスポンスを作ることも可能
- まるごと偽レスポンスをサーバ側にキャッシュさせる(→ キャッシュ汚染)ことで、別のユーザにも偽のレスポンスを返すことができる
- redirect_urlに改行文字
対策
- ヘッダの出力を、言語やフレームワークのAPIで行う
- ちゃんと対策してくれてるはずなので
- APIが無ければ、ヘッダの値に改行が含まれないよう処理する
- 改行以降の文字を削除するとか
- 改行コードを削除するとか
- LocationにURLを入れる場合はURLエンコーディング
1.8 メールヘッダ・インジェクション
- 参考: メールヘッダ・インジェクションとは | 分かりやすく図解で解説
- HTTPヘッダ・インジェクションとだいたい同じ
- フォームからの問い合わせを管理者にメールで通知するなど、ユーザの入力内容をメールで送信する機能にありがち
- メールヘッダ中の値(Subject, To, Fromなど)をユーザからの入力で動的に変えている場合、ユーザの入力に改行とヘッダ要素が含まれていると改ざんされる
- 例:Subjectにユーザの入力テキストを入れる
対策
- ユーザからの入力をメールヘッダに入れず、全て本文に入れる
- 送信処理を、メール送信用のAPIで行う
- ヘッダの値に改行が含まれないようにする
1.9 クリックジャッキング
- CSRFに似ている
- 罠サイト上にiframeで元サイトを開き、透明にする
- 見た目は罠サイトだが、要素は元サイト
- 元サイトにログインした状態で罠サイトをクリックすると、元サイト上で操作したのと同じになる
- (透明なのでフォーム等は使えず、元サイトの中のクリックで操作する機能に限られる)
- 注意が必要な機能:
- ユーザの個人情報の公開範囲を設定する部分
対策
- レスポンスヘッダにX-Frame-Optionsを設定
- 実行する直前で再度パスワードの入力を求める
- 重要な処理をマウスだけで完結させない
1.10 バッファオーバーフロー
- 参考:
- wikipediaよりざっくり:
- 古典的バッファオーバーフロー
- 確保されたバッファより大きいデータを入れてしまい、隣のデータが上書きされる
- 隣に権限を示すフラグなどが入っていた場合、管理者権限が乗っ取られることになる
- スタック型
- スタック領域:コールスタックを格納する領域
- コールスタック:スタックフレームを並べたもの
- スタックフレーム:関数内の変数や実行後に戻る呼び出し元関数のポインタの情報
- コールスタック:スタックフレームを並べたもの
- 関数のスタックフレーム内で確保していたローカル変数用の領域を超えるデータをその変数に入れてしまい、スタックフレーム内で近くに書かれているリターンアドレスが上書きされる
- 悪意あるコードを同時に送りつけられ、リターンアドレスがそれを指すよう上書きされると、実行されてしまう
- (どうやってうまいことリターンアドレス部分にデータを書き込むかについても書かれているけど難しすぎた)
- スタック領域:コールスタックを格納する領域
- ヒープ型
- ヒープ領域:
malloc
などで動的に確保された、計算や操作に利用する領域 - ヒープ領域を利用する(= 動的にメモリ確保を行う)関数を対象にする
- 関数が2つのヒープ領域を確保しているとき、1つをオーバーフローさせることでもう1つの領域にデータを書き込む
- ヒープ領域:
- 結果↓
- クラッシュさせる
- write-what-where状態(任意の場所に任意の値を書き込める状態)
- 任意のコードを実行できる
- 古典的バッファオーバーフロー
対策
- 直接メモリにアクセスできない言語を使う
- ライブラリを最新のバージョンにして使う
- PHP等のライブラリでバッファオーバーフロー脆弱性が見つかったケースも
- 直接メモリにアクセスする必要がある場合は最小限に
1.11 アクセス制御や認可制御の欠落
- 非公開の情報にアクセスするためにパスワードなど他人に知られない前提の情報を使う
- 認証後、認可に必要な情報をログイン中のユーザ以外から見えないようにする
- 注文番号で検索でき、かつ注文番号が取得・推測可能なものであれば、結果的に誰でも見えてしまう
- 認可に使うキーとなる情報をGETやPOSTで渡すのもNG