はじめに
面接でセキュリティを意識していることを何か聞かれて明確に答えられていなかったため基礎のWebアプリケーションのセキュリティについて学ぶ
1章 Webアプリケーションの脆弱性とは
脆弱性とは、「悪用できるバグ」
- 個人情報などの秘密情報を勝手に閲覧
- Webサイトの内容を書き換え
- サイトを閲覧した利用者のPCをウイルス感染
- 別の利用者になりすまし、秘密情報の閲覧、投稿、買い物、送金
- Webサイトを利用不能にする
- オンラインゲームなどで無敵、アイテム複製
脆弱性があるとダメな理由
- 経済的損失
- 法的な要求
- 利用者が回復不可能なダメージを受ける
- Webサイト利用者に「安全である」と嘘をつく
- ボットネットワーク構築(感染したPCでさらに攻撃するためのネットワーク)に加担する
脆弱性が生まれる理由
-
バグによるもの
SQLインジェクションやクロスサイト・スクリプティング(XSS) -
チェック機能不足
ディレクトリ・トラバーサル脆弱性
2章 実習環境のセットアップ
割愛
ご自身のパソコンに仮想環境(VMwareなど)でwindowsを起動し言語をインストール
Fiddler(Webアプリケーションデバッグ用ツール)はインストールする
3章 Webセキュリティの基礎 ~HTTP、セッション管理、同一性成元ポリシー
HTTPとセッション管理
リクエストメッセージ
GET /31/31-001.php HTTP/1.1
GET...メソッド
/31/31-001.php...リクエストURL
HTTP/1.1...プロトコルバージョン
ステータスライン
HTTP/1.1 200 OK
HTTP/1.1...プロトコルバージョン
200...ステータスフレーズ
OK...テキストフレーズ
- パーセントエンコーディング
特殊記号や日本語などURLに使用できない文字をURL上に記述する場合に用いられる。対象の文字をバイト単位で「%XX」という形式で表す。XXはバイトの16進数表記です。
GETとPOSTの使い分け
- GETメソッドは参照(リソースの取得)のみ用いること
- GETメソッドは副作用がないこと(副作用とはリソースの取得以外の作用)
- 機密情報の雄真にはPOSTメソッドを用いる
機密情報をPOSTで送る理由
- URL上に指定されたパラメータがReferer経由で外部に漏洩
- URL上に指定されたパラメータがアクセスログに残る
一つも当てはまらない場合はGET
- データ更新など副作用を伴うリクエスト
- 秘密情報を送信する
- 送信するデータの総量が多い
hiddenパラメータは書き換えが可能である。
hiddenパラメータのメリット
- 利用者自身からは書き換えできるが、情報漏洩や第三者からの書き換えに対して堅牢
- クッキーやセッション変数は、セッションIDの固定化攻撃に弱い
- 上記理由で利用者自身にも書き換えられたら困る認証や許可に関する情報はセッション変数に、それ以外はhiddenパラメータに保存することを検討する
ステートレスなHTTP認証 Basic認証
- 一度Basicn認証に成功すると、そのあとはディレクトリへのリクエストには、ブラウザが自動的にAuthorizationヘッダを付与してくれるため、見かけ上は一回だけ認証ダイアログが表示されるので認証状態が保持されているように見える。
実際にはリクエスト毎にIDとパスワードが送出され、認証状態はどこにも保存されていません。そのためログアウトという概念もない
クッキーとセッション管理
- クッキー値を覚えたブラウザは、そのあと同じサイトにリクエストを送信する際に覚えたクッキー値を送信する。有効期限が設定できるが、設定していないクッキーの場合ブラウザを終了させるまで有効
クッキーによるセッション管理
アプリケーションデータを保持する目的でクッキーそのものに値を入れることはあまりない
- クッキーが保持できる値の個数や文字列長には制限がある
- クッキーの値は利用者本人には参照・変更できるので、秘密情報の格納に向かない
上記のためクッキーには「整理番号」としてのセッションIDを格納しておき、実際の値はサーバー側で管理する方法が用いられる
セッションIDは連番だと悪用されるので、十分な桁数の乱数を用いる。必要な要件は以下
1.第三者がセッションIDを推測できないこと
2.第三者からセッションIDを強制されないこと
3.第三者にセッションIDが漏洩しないこと
セッションIDは暗号論的擬似乱数生成機を用いて生成する。Webアプリケーション開発ツールで提供されるセッションIDを利用するべき
正規利用者に対してセッションIDを強制する攻撃:セッションIDの固定化攻撃
- こちらの防ぎ方は認証されたタイミングでセッションIDを変更する
セッションID漏洩の原因
- クッキー発行の際の属性に不備がある
- ネットワーク的にセッションIDが盗聴される
- クロスサイト・スクリプティングなどアプリケーションの脆弱性により漏洩する
- PHPやブラウザなどプラットフォームの脆弱性により漏洩する
- セッションIDをURLに保持している場合は、Refererヘッダから漏洩する
セッションIDをネットワーク盗聴から保護するにはSSL(Secure Socket Layer)による暗号化が有効だが、クッキーを発行する際に属性指定に注意が必要
クッキーの属性
属性 | 意味 |
---|---|
Domain | ブラウザがクッキー値を送信するサーバーのドメイン |
Path | ブラウザがクッキー値を送信するURLのディレクトリ |
Expires | クッキー値の有効期限。指定しない場合はブラウザの終了まで |
Secure | SSLの場合のみクッキーを送信 |
HttpOnly | この属性が指定されたクッキーはJavaScriptからアクセスできない |
クッキーのDomain属性
- デフォルトではクッキーをセットしたサーバーにのみ送信される。セキュリティ上はこれがもっとも安全だが、複数のサーバに送信されるクッキーを生成したい場合もある、その場合Domain属性を使う
Domain属性を指定しない状態がもっともクッキーの送信範囲が狭く、安全な状態である。なのでDomain属性は通常は設定しないものとする
クッキーのセキュア属性
- secureという属性をつけたクッキーは、SSL通信の場合のみサーバーに送信される。一方、セキュア属性のついてないクッキーは、SSL通信かどうか関係なく、常にサーバーに送信される
クッキーのHttpOnly属性
- HttpOnly属性は、JavaScriptからアクセスできないクッキーを設定する
セッションIDを盗み出す典型例は、クロスサイト・スクリプティング攻撃によりJavaScriptを悪用してクッキーを盗み出すというもので、クッキーにHttpOnly属性をつけておくと、JavaScriptによりクッキーを盗み出すことができなくなる。
完全に防ぎ切ることはできないが、攻撃を難しくすることができる。つけてても悪影響は通常ないので、セッションIDにはこの属性をつけておく
受動的攻撃と同一生成元ポリシー
攻撃方法
能動的攻撃
- 攻撃者がwebサーバーに対して直接攻撃すること。代表はSQLインジェクション攻撃
受動的攻撃
- 攻撃者がサーバーを直接攻撃するのではなく、webサイトの利用者に罠を仕掛けることにより、罠を閲覧したユーザを通してアプリケーションを攻撃する
例)怪しいサイトを見てマルウェア感染
正規サイトを悪用する受動的攻撃
1.攻撃者はあらかじめ正規サイトを攻撃してコンテンツに仕掛けを仕込む
2.3.正規サイトの利用者が仕掛けを含むコンテンツを閲覧する
4.マルウェア感染が起こる
正規サイトに罠を仕込む手法 - FTPなどのパスワードを不正入手してコンテンツを書き換える
- Webサーバーの脆弱性をついた攻撃によりコンテンツを書き換える
- SQLインジェクション攻撃によりコンテンツを書き換える
- SNSなど利用者が投稿できるサイト機能のクロスサイト・スクリプティング脆弱性を悪用する
サイトをまたがった受動的攻撃
1.利用者が罠サイトを閲覧
2.罠サイトから、仕掛けを含むHTMLをダウンロードする
3.HTMLの仕掛けが発動して正規サイトに攻撃のリクエストを送信する
4.正規サイトからJavaScriptなどの仕掛けを含むレスポンスが返る
このパターンの攻撃の典型としては、3のリクエストでwebアプリケーションを攻撃するタイプがクロスサイト・リクエストフォージェリ(CSRF)、4のレスポンスによりブラウザを介して攻撃するタイプがクロスサイト・スクリプティング(XSS)やHTTPヘッダ・インズエクションである
ブラウザはどのようにして攻撃を防ぐのか
サンドボックスという考え方
- ブラウザ上では、JavaScriptやJavaアプレット、Adobe Flash Player、ActiveXなど、サイトを閲覧した状態でプログラムを実行する機能が提供されている。利用者のブラウザ上での悪意のあるプログラムが動かないように、JavaScriptなどは安全性を高める機能を提出している。基本的な考えは以下になる
1.利用者に配布元を確認させた上で、利用者が許可した場合のみ実行する
2.プログラムの「できること」を制限するサンドボックスという環境を用意する
一般的にサンドボックスでは以下のことが制限される
・ローカルファイルへのアクセスの禁止
・プリンタなどの資源の利用禁止(画面表示は可能)
・ネットワークアクセスの制限(同一生成元ポリシー)
同一生成元ポリシーとは。JavaScriptによるサイトをを跨ったアクセスを禁止するセキュリティ上の制限。異なるホストに置かれたJavaScriptからのアクセスは拒否される
同一生成元である条件
- URLのホスト(FQDN)が一致している
- スキーム(プロトコル)が一致している
- ポート番号が一致している
それでもアプリケーションに脆弱性があると受動的攻撃を受ける場合がある、その代表例がクロスサイト・スクリプティング(XSS)攻撃
JavaScript以外のクロスドメインアクセス
- frame要素とiframe要素
img要素
img要素のsrc属性はクロスドメインの指定が可能、意図しないサイトに画像が貼られることを禁止したいという場合には、画像に対するRefererヘッダをチェックするという手法がある
script要素
script要素にsrc属性を指定すると他のサイトからJavaScriptを読み込むことができる
サイトAのドメインでscriptを読み込み、サイトBのJavaScriptを起動することでサイトAのクッキーが取得できる。
JSONPという手法で起こることがある。
CSS
CSSはクロスドメインでの読み込みが可能、HTMLのlink要素のほか、CSS内から@import、JavaScriptからaddImportメソッドが使える
form要素のaction属性
form要素のaction属性もクロスドメインの指定が可能、またformの送信(submit)はJavaScriptから常に(action先がクロスドメインであっても)操作できる
クロスサイト・リクエストフォージェリ(CSRF)攻撃が主
4章 Webアプリケーションの機能別に見るセキュリティバグ
脆弱性はどこで発生するのか
出力 | 脆弱性の種類 |
---|---|
ブラウザ | クロスサイト・スクリプティング、HTTPヘッダ・インジェクション |
DB/SQL(RDB) | SQLインジェクション |
外部コマンド(シェル) | OSコマンド・インジェクション |
メール | メールヘッダ・インジェクション |
ファイル | ディレクトリ・トラバーサル |
重要な処理 | クロスサイト・リクエストフォージェリ |
認証 | セッションフィクセーション、認証不備 |
認可 | 認可不備 |
- HTMLの出力(クロスサイト・スクリプティング)
- HTTPヘッダの出力(HTTPヘッダ・インジェクション)
- SQLの呼び出し(発行)(SQLインジェクション)
- シェルコマンドの呼び出し(OSコマンド・インジェクション)
- メールヘッダおよび本文の出力(メールヘッダ・インジェクション)
脆弱性は以下のことがわかる
- 脆弱性には処理に起因するものと出力に起因するものがある
- 入力に起因する脆弱性はない
- 出力に起因する脆弱性には「インジェクション」という単語がつくものが多い
インジェクション系脆弱性とは
外部から流し込んだシングルクォート「'」とセミコロン「;」によりSELECT文が終了させられた後。DELETE FROMというSQL文が追加される。これがSQLインジェクション
原因はSQL文の構造を変化させられること
入力処理とセキュリティ
入力処理では、入力値に対して以下の処理を行う
1.文字エンコーディングの妥当性検証
2.文字エンコーディングの変換(必要な場合のみ)
3.パラメータ文字列の妥当性検証
上記をやる理由
- 1.の文字エンコーディングの妥当性検証を行う理由は、文字コードを使った攻撃手法があるため
- 2.の文字エンコーディングの変換が必要なケースは、HTTPメッセージとプログラム内部で文字エンコーディングが異なる場合
- 3.アプリケーションの仕様に基づいて行う、セキュリティ上の保険的な対策にもなる
入力値検証の目的
入力値検証のないアプリケーションでは、以下のような現象が起こる
- 数値のみを受け付ける項目に英字や記号を入力して、データベースエラーになる
- 更新処理が途中でエラーになり、データベースの不整合が発生する
- 利用者が多数の項目を入力して実行ボタンをクリックしたら内部エラーとなり、入力を最初からやり直す羽目になる
- メールアドレスの入力を忘れているのにアプリケーションがメール送信処理を実行する
入力値検証の目的は以下の通り
- 入力血の間違いを早期に発見して再入力を促すことにより、ユーザビリティ(使いやすさ)を向上する
- 間違った処理を継続することによるデータの不整合などを防ぎ、システムの信頼性を向上させる
入力値検証のセキュリティ
主目的はセキュリティのためではありませんが、セキュリティのために役立つ場合もある。役立つ場合は以下のケース
- SQLインジェクション対策が漏れていたパラメータがあるが、英数字のみ許可していたので実害に至らない
- PHPのバイナリセーフでない関数(後述)を使っているが、入力段階で制御文字をチェックしているので実害に至らない
- 表示処理の関数に文字エンコーディングの指定を怠っているが、入力段階で不正な文字エンコーディングをチェックしているので実害に至らない
バイナリセーフという考え方とヌルバイト攻撃
バイナリセーフとは、入力値がどんなバイト列であっても正しく扱えることを意味する
ヌルバイトを使った攻撃手法が知られており、ヌルバイト攻撃と呼ばれてます。ただし、ヌルバイト攻撃は単独で被害を与えるものではなく、他の脆弱性の対策を回避するために用いられる
入力値検証の基準はアプリケーション要件
制御文字のチェック
文字数のチェック
入力値検証の対象はすべてのパラメータ
表示処理に伴い問題
表示処理が原因で発生するセキュリティ上の問題は以下
- クロスサイト・スクリプティング
- エラーメッセージからの情報漏洩
クロスサイト・スクリプティング
webアプリケーションには外部からの入力などに応じて表示が変化する箇所があり、この部分のHTML生成の実装に問題があると、クロスサイト・スクリプティングという脆弱性が発生する。
XSS脆弱性がある場合は以下の影響がある
- サイト利用者のブラウザ上で、攻撃者の用意したスクリプトの実行によりクッキー値を盗まれ、利用者がなりすましの被害にある
- 同じくブラウザ上でスクリプトを実行させられ、サイト利用者の権限でWebアプリケーションの機能を悪用される
- webサイト上に偽の入力フォームが表示され、フィッシングにより利用者が個人情報を盗まれる
攻撃手法と影響
- クッキー血の盗み出し
- JavaScriptによる攻撃
- 画面の書き換え
反射型XSSと持続性XSS
- 攻撃用JavaScriptが、攻撃対象サイトとは別のサイト(罠サイトやメールのURL)にある場合を反射型XSS
- 持続型XSSは、WebメールやSNSなどが典型的な攻撃ターゲット
脆弱性が生まれる原因
- XSS脆弱性が生じる原因は、HTML生成の際に、HRMLの文法上特別な意味を持つ特殊記号(メタ文字)を正しく使っていないことであり、それにより、開発者の意図しない形でHTMLやJavaScriptを注入・変換させる現象がXSS。メタ文字の持つ特別な打ち消し、文字そのものとして扱うためには、エスケープという処理を行う。HTMLのエスケープは、XSS解消のためには非常に重要
XSS対策の基本
- 要素内容については「<」と「&」をエスケープする
- 属性値については、ダブルクォートで囲って、「<」と「"」と「&」をエスケープする
- 入力値検証
- クッキーにHttpOnly属性を付与する
- TRACEメソッドの無効化
これは、クロスサイト・トレーシングという攻撃への対策
クロスサイト・スクリプティング(発展編)
- URLをプログラムで生成する場合、httpスキームとhttpsスキームのみを許可するようにチェックする
- http: または https: で始まるURL
- スラッシュ「/」で始まる相対URL
リンク先ドメインのチェック
リンク先として任意のドメインのURLを指定できる場合
- リンク先URLを検証して、URLが外部ドメインである場合はエラーにする
- 外部ドメインへのリンクであることを利用者に注意喚起するためのクッションページを表示する
JavaScriptの動的生成
イベントハンドラのXSS、JavaScriptの文字列リテラルの動的生成の対策
- 1.JavaScriptの文法から、引用符(「"」または「'」)と「\」や改行をエスケープする
- 2.イベントハンドラ中の場合は、1の結果を文字参照によりHTMLエスケープして、ダブルクォーと「"」で囲む
- 3.script要素内の場合は、1の結果に「</」という文字列が出現しないようにする
Unicodeエスケープによる対策
JavaScriptの動的生成には危険が伴うので、英数字以外を全てエスケープする手法
DOM based XSS
JavaScriptによりクライアント側で表示処理する箇所があり、そこに脆弱性がある場合のXSS
HTMLタグやCSSの入力を許す場合の対策
HTMLテキストを構文解析して必要な要素のみを抽出するライブラリを使用することが望ましい
エラーメッセージからの情報漏洩
- エラーメッセージに攻撃者にとって有益なアプリケーションの内部情報が含まれる
- 意図的な攻撃として、エラーメッセージに秘密情報(個人情報など)を表示させられる
SQL呼び出しに伴う脆弱性
SQLインジェクション
SQLインジェクションは、SQLの呼び出し方に不備がある場合に発生する脆弱性です。
- データベース内のすべての情報が外部から盗まれる
- データベースの内容が書き換えられる
- 認証を回避される(IDとパスワードを用いずにログインされる)
- そのほか、データベースサーバー上のファイルの読み出し、書き出し、プログラムの実行などを行われる
SQLインジェクションの攻撃手段
- UNION SELECTを用いた情報漏洩
- SQLインジェクションによる認証回避、データ改竄
- OSコマンドの実行
- ファイルの読み出し
- ファイルの書き出し
- HTTPリクエストにより他のサーバーを攻撃
脆弱性が生まれる原因
SQLインジェクションとは開発者の意図しない形にSQL文が改変されること、その典型的な原因はリテラルの扱いにある
対策
- プレースホルダーによりSQL文を組み立てる
- アプリケーション側でSQL文を組み立てる際に、リテラルを正しく構成するなど、SQL文が変更されないようにする
- 詳細なエラーメッセージの抑止
- 入力値の妥当性検証
- データベースの権限設定
「重要な処理」の際に混入する脆弱性
クロスサイト・リクエストフォージェリ(CSRF)
「重要な処理」の受付に際して、利用者の意図したリクエストであることを確認する必要がありますが、この確認処理が抜けていると、罠のサイトなどを閲覧しただけで、利用者のブラウザから勝手に「重要な処理」を実行させられる場合がある
CSRFとXSSの違い
- CSRFはリクエストに対するサーバー側の処理を悪用するもの
- XSSはリクエストに含まれるスクリプトはオウム返しに利用者に返されブラウザ上で実行される
CSRFの脆弱性が生まれる原因
- form要素のaction属性にはどのドメインのURLでも指定できる
- クッキーに保管されたセッションIDは、対象サイトに自動的に送信される
対策
- CSRF対策の必要なページを区別する
- 正規利用者の意図したリクエストを区別できるように実装する
- 秘密情報(トークン)の埋め込み
- パスワード再入力
- Refererのチェック
CSRF攻撃への保険的対応
重要な処理の実行後に、対象利用者の登録済みメールアドレスに対して、処理内容の通知メールを送信することを推奨します
セッション管理の不備
第三者がセッションIDを知るための手段は3つ
- セッションIDの推測
- セッションIDの盗み出し
盗み出す手法は以下になる
1.クッキーの生成の際の属性の不備により漏洩
2.ネットワーク的にセッションIDが盗聴される
3.クロスサイト・スクリプティングなどアプリケーションの脆弱性により漏洩する
4.PHPやブラウザなどプラットフォームの脆弱性により漏洩する
5.セッションIDをURLに保持している場合は、Refererヘッダから漏洩する
セッションIDの盗み出しに悪用可能なアプリケーション脆弱性の典型例は以下
1.クロスサイト・スクリプティング(XSS)
2.HTTPヘッダ・インジェクション
3.URLに埋め込まれたセッションID - セッションIDの強制
セッションハイジャックの影響
- 利用者の重要情報の閲覧
- 利用者の持つ権限での操作
- 利用者のIDによるメール、ブログなどへの投稿、設定の変更など
攻撃手法と影響
1.対象アプリケーションからセッションIDを集める
2.セッションIDの規律性の仮説を立てる
3.推測したセッションIDを対象アプリケーションで試す
脆弱性が生まれる原因
- 主要なWebアプリケーション開発ツールはセッション管理機構を備えている
- 安全なセッションID生成プログラムを開発することは技術的難易度が高い
対策
- PHPのセッションIDのランダム性を改善する方法
1.リモートIPアドレス
2.現在時刻
3.乱数(暗号論的擬似乱数生成形ではない)
脆弱性が生まれる原因
- 2000年前後に主にプライバシー上の理由から「クッキー有害論」が起こり、クッキーを避けようという機運が一部あった
- NTTドコモ社の携帯電話ブラウザが最近までクッキーに対応していなかったので、携帯電話向けWebアプリケーションは今でもURL埋め込みのセッションIDが主流である
対策
URL埋め込みのセッションIDを使わないためには、クッキーにセッションIDを保存する
クッキーのみにセッションIDを保存するサイトのセッションIDの固定化
クッキーのセッションIDを外部から設定することは通常できないが、ブラウザやWebアプリケーションに脆弱性があれば、可能。以下がクッキーを第三者が設定できる脆弱性
- クッキーモンスター問題
- クロスサイト・スクリプティング脆弱性
- HTTPヘッダ・インジェクション脆弱性
脆弱性が生まれる原因
セッションIDの固定化に対する脆弱性が生まれる第一の原因は、セッションIDを外部から強制できるところ
対策
- セッションIDをURLに埋め込みにしない
- クッキーモンスター問題のあるブラウザを使わない
- クッキーモンスター問題の発生しやすい地域型ドメインを使わない
- クロスサイト・スクリプティング脆弱性をなくす
- HTTPヘッダ・インジェクション脆弱性をなくす
- その他、クッキーを書き換えられる脆弱性をなくす
4.6節まとめ
セッション管理不備の対策は以下
- セッション管理機構を自作せずWebアプリケーション開発ツールのものを使う
- クッキーにセッションIDを保存する
- 認証成功時にセッションIDを変更する
- 認証前にはセッション変数に秘密情報を保持しない
リダイレクト処理にまつわる脆弱性
リダイレクト処理に際して発生する代表的な脆弱性は以下
- オープンリダイレクト脆弱性
- HTTPヘッダ・インジェクション脆弱性
脆弱性が生まれる原因
オープンリダイレクト脆弱性が生まれる原因は
- リダイレクト先のURLを外部から指定できる
- リダイレクト先のドメインのチェックがない
オープンリダイレクトが差し支えない場合
- もともと外部のドメインに遷移する仕様である
- 利用者にとって外部ドメインに遷移することが自明である
対策
- リダイレクト先のURLを固定する
- リダイレクト先のURLを直接指定せず番号指定にする
- リダイレクト先のドメインをチェックする
HTTPヘッダ・インジェクション
リダイレクトやクッキー発行など、外部からパラメータを元にHTTPレスポンスヘッダを出力する際に発生する脆弱性
被害者のブラウザ上で以下のどちらか、または両方が引き起こされる
- 任意のレスポンスヘッダの追加
- レスポンスボディの偽造
HTTPヘッダ・インジェクション脆弱性が悪用した攻撃をHTTPヘッダ・インジェクション攻撃と呼ぶ
WebアプリケーションにHTTPヘッダ・インジェクション脆弱性があると、以下の影響がある
- 任意のクッキーの作成
- 任意のURLへのリダイレクト
- 表示内容の改変
- 任意のJavaScript実行によるXSSと同様の被害
脆弱性が生まれる原因
HTTPレスポンスヘッダはテキスト形式で1行に1つのヘッダ定義できます。すなわち、ヘッダとヘッダは改行で区切られることになります。この性質を悪用して、リダイレクト先URLやクッキー値として設定されるパラメータ中に改行を挿入した場合に、改行がそのままレスポンスとして出力されることが、HTTPヘッダ・インジェクション脆弱性の原因です
対策
HTTPヘッダ・インジェクション脆弱性の最も確実な対策は、外部からのパラメータをHTTPレスポンスヘッダとし出力しないこと
- リダイレクト処理にはできるだけ専用のAPI(ライブラリ関数)を仕様する
- 以下のいずれかを実施する
1.リダイレクト先は固定にする
2.外部から指定するリダイレクト先のURLは、必ず文字種とドメイン名をチェックする
クッキー出力にまつわる脆弱性
クッキーにまつわる脆弱性は大別すると以下
- クッキーを利用すべきでない目的でクッキーを使っている
- クッキーの出力方法に問題がある
クッキー出力時に発生しやすい脆弱性
- HTTPヘッダ・インジェクション脆弱性
- クッキーのセキュア属性不備
脆弱性が生まれる原因
クッキーのセキュア属性不備の直接原因は、単にセキュア属性をつけていない
- 開発者がセキュア属性について知らない
- セキュア属性をつけるとアプリケーションが動かなくなる
トークンを用いた対策
セッションIDを保持するクッキーにセキュア属性がつけられない場合、トークンを利用してセッションハイジャックを阻止する方法がある。トークンを保持するクッキーにセキュア属性をつけることによって、HTTPのページとHTTPSのページでセッションを共有しつつ、仮にセッションIDを盗聴された場合でもHTTPSのページはセッションハイジャックを阻止できる
トークンにより安全性が確保できる理由
- トークンは認証成功時に一度だけサーバーから出力される
- トークンはHTTPSのページで生成される(サーバー→ブラウザ)
- トークンは確実に暗号化されてブラウザから送信される(ブラウザ→サーバー)
- HTTPSのページを閲覧するにはトークンが必須
メール送信の問題
メール送信の問題は以下
- メールヘッダ・インジェクション脆弱性
メールメッセージの宛先や件名などヘッダフィールドに改行を挿入することにより、新たなフィールドを追加したり、本文を改竄する - hiddenパラメータによる宛先保持
hiddenパラメータの送信先アドレスを任意のアドレスに変更することにより、迷惑メールの送信に悪用される - メールサーバーよる第三者中継
メールサーバーの設定に問題があると、そのメールサーバーの受信者でも発信者でもない、第三者のメールを中継する場合がある
対策
- メール送信には専用のライブラリを使用する
1.外部からのパラメータをメールヘッダに含ませないようにする
2.外部からのパラメータには改行を含まないようにメール送信時にチェックする
ファイルアクセスにまつわる問題
- Webサーバー内のファイルに対する不正アクセス(ディレクトリ・トラバーサル)
Webサーバー内のファイルの閲覧→重要情報の漏洩
Webサーバー内のファイルの改ざん、削除
1.webコンテンツ改竄によるデマ、誹謗中傷の書き込み
2.マルウェアのサイトに誘導する仕組みの書き込み
3.スクリプトファイルや設定ファイルの削除によるサーバー機能停止
4.スクリプトファイル改ざんによる任意のサーバースクリプト実行 - OSコマンドの呼び出し(OSコマンド・インジェクション)
脆弱性が生まれる原因
- ファイル名を外部から指定することができる
- ファイル名として、絶対パスや相対パスの形で異なるディレクトリを指定できる
- 組み立てたファイル名に対するアクセスの可否をチェックしてない
対策
- 外部からファイル名を指定できる仕様を避ける
- ファイル名をディレクトリ名が含まれないようにする
- ファイル名を英数字に限定する
OSコマンド呼び出し際に発生する脆弱性
WebアプリケーションにOSコマンド・インジェクション脆弱性があると、外部の攻撃者からの様々な攻撃を受けることになり危険
典型的には以下のようなシナリオ
1.攻撃用ツールを外部からダウンロード
2.ダウンロードしたツールに実行権限を与える
3.OSの脆弱性を内部から攻撃して管理者権限を得る
4.Webサーバーは攻撃者の思うのままになる
Webサーバーの悪用は以下が可能
- webサーバー内のファイル閲覧・改ざん・削除
- 外部へのメールの送信
- 別のサーバーへの攻撃(踏み台)
脆弱性が生まれる原因
- シェル経由でOSコマンドを呼び出す際に、シェルのメタ文字がエスケープされていない
- シェル機能を呼び出せる関数を使用している
- シェルを呼び出す機能のある関数(system,openなど)を利用している
- シェル呼び出しの機能のある関数にパラメータを渡している
- パラメータ内に含まれるシェルのメタ文字をエスケープしていない
対策
OSコマンド・インジェクション脆弱性は以下で対策するよう推奨
- OSコマンド呼び出しを使わない実装方法を選択する
- シェル呼び出し機能のある関数の利用を避ける
- 外部から入力された文字列をコマンドラインのパラメータに渡さない
- OSコマンドに渡すパラメータを安全な関数によりエスケープする
ファイルアップロードにまつわる問題
アップローダに対する攻撃には以下がある
- アップロード機能に対するDoS攻撃
- サーバー上のファイルをスクリプトとして実行する攻撃
- 仕掛けを含むファイルを利用者にダウンロードさせる攻撃
- ファイルの権限を越えたダウンロード
脆弱性が生まれる原因
アップロードファイルをスクリプトとして実行可能な脆弱性が生まれる条件は、以下の両方
- アップロードしたファイルが公開ディレクトリに保存される
- アップロード後のファイル名として、スクリプトを示す拡張子が指定できる
対策
アップロードしたファイルがスクリプトとして実行される条件は、ファイルを公開ディレクトリに保存することと、スクリプトとして実行可能な拡張子を利用者が指定できることの2点を潰す
インクルードにまつわる問題
ファイルインクルード攻撃による影響は以下の通り
- webサーバー内のファイルの閲覧による情報漏洩
- 任意スクリプトの実行による影響。典型的には以下の影響
1.サイト改ざん
2.不正な機能実行
3.他サイトへの攻撃(踏み台)
対策は
- インクルードするパス名に外部からのパラメータを含まない
- インクルードするパス名に外部からのパラメータを含める場合は、英数字に限定する
evalにまつわる問題
evalインジェクションによる影響は、OSコマンド・インジェクション攻撃と同じ
- 情報漏洩
- サイト改ざん
- 不正な機能実行
- 他サイトへの攻撃(踏み台)
対策は
- evalに相当する機能を使わない
- evalの引数には外部からのパラメータを含めない
- evalに与える外部からのパラメータを英数字に限定する
共有資源に関する問題
共有資源とは、複数のプロセスやスレッドから同時に利用している変数、共有メモリ、ファイル、データベースなどのこと。共有資源に対する排他制御が不十分な場合、競合状態の脆弱性の原因となる場合がある。
- 別人の個人情報などが画面に表示される
- データベースの不整合
- ファイルの内容の破壊
対策は
- 可能であれば共有資源の利用を避ける
- 共有資源に対する適切な排他制御を行う
5章 代表的なセキュリティ機能
認証
認証とは、利用者が確かに本人であることを何らかの手段で確認することを指す
ログイン機能
ログイン機能に対する攻撃が成立すると、第三者が利用者になりすますことができる。これを不正ログインと呼び、認証機能に対する攻撃の典型例は以下
- SQLインジェクション攻撃によるログイン機能のバイパス
- SQLインジェクション攻撃によるパスワードの入手
- ログイン画面に対するパスワード試行
- ソーシャルハッキングにおけるパスワード入手
- フィッシングによるパスワード入手
不正ログインを防ぐためには
- SQLインジェクションなどセキュリティバグ(狭義の脆弱性)をなくす
ログイン機能の特性上発生しやすい脆弱性は以下
1.SQLインジェクション
2.セッションIDの固定化
3.クッキーのセキュア属性不足
4.オープンリダイレクタ脆弱性
5.HTTPヘッダ・インジェクション - パスワードを予想困難なものにする
- 積極的なパスワードポリシーのチェック
総当たり攻撃への対策
基本的なアカウントロック
webアプリケーションの場合、最も基本的なアカウントロックは以下
- ユーザID毎にパスワード間違いの回数を超える
- パスワード間違いの回数が上限値を超えると、アカウントをロックする。ロックされたアカウントはログインできなくなる
- アカウントロックが発生した場合はメールなどで対象利用者と管理者に通知する
- 正常にログインした場合は、パスワード間違いのカウンタをクリアする
パスワードの保存方法
SQLインジェクションなどによりデータベースの情報が漏洩しても、パスワードだけは悪用されない形で保護すること
webアプリケーションの開発言語には暗号化のライブラリが用意されているので、パスワードの暗号化・復号のプログラミング自体は難しくないが以下が課題になる
- 安全な暗号アルゴリズムの選定
- 鍵の生成
- 鍵の保管
- 暗号アルゴリズムの危殆化(きたいか)した場合の再暗号化
対策は
-
ソルト
ハッシュの元データに追加する文字列のことで、見かけのパスワードを長くするとともに、ソルトをユーザ毎に異なるものにすることで、パスワードが同じでも異なるハッシュ値が生成されるようになる
ソルトの要件は、ある程度の長さに確保する、ユーザー毎に異なるものにする -
ストレッチング
ハッシュの計算を繰り返し行うことによって、計算時間を伸ばすこと
自動ログイン
自動ログインの安全な実装方法
- セッションの寿命を延ばす
保持するクッキーにExpires属性(有効期限)を設定できる言語やミドルウェアを使っている場合 - トークンを使う
ログイン時にトークンを発行 - チケットを使う
認証チケットによる自動ログイン
3方式の比較した時にトークン方式が好ましく、理由が以下
- 自動ログインを選択しない利用者に影響を与えない
- 複数端末からログインしている場合に一斉にログアウトできる
- 管理者が、特定利用者のログイン状態をキャンセルできる
- クライアント側に秘密情報が渡らないので解析されるリスクがない
エラーメッセージの要件
IDが間違っているorパスワードが間違っているかが攻撃者にわからなくするため
「IDまたはパスワードが違うか、アカウントがロックされています」
などにしたほうがいい
ログアウト機能
ログアウト処理を安全確実に行う方法は、セッションを破棄すること
第三者によるログアウト強制の影響が軽微な場合はCSRF対策を省略することも可能
ログアウト処理の要件は以下
- ログアウト処理は副作用があるのでPOSTメソッドでリクエストする
- ログアウト処理ではセッションを破棄する
- 必要な場合、 CSRF対策の対象とする
アカウント管理
ユーザー登録
以下のようなセキュリティ上の注意点がある
- メールアドレスの受信確認
- ユーザIDの重複防止
- ユーザの自動登録への対処(任意)
- パスワードに関する注意
ユーザ登録処理に混入しやすい脆弱性は以下
- SQLインジェクション脆弱性
- メールヘッダ・インジェクション脆弱性
メールアドレスの受信確認
パスワードリマインダ機能のあるサイトの場合、パスワード通知メールが誤って別人に届くと、セキュリティ上の問題に直結する。このため登録されたメールアドレスに送信されるメールを利用者自身が受信できることを確認するべき、具体的には以下の内容
- メールにトークンつきURLを添付し、そのURLから処理を継続
- メールアドレスを入力した後、トークン(確認番号)入力画面に遷移する。トークンは、指定したメールアドレスにメール送信される
ユーザIDの重複防止
ユーザIDは一意出なければならない
以下のようなのはNG
- パスワードが違えば同じIDで登録できる
- ユーザIDに一意制約をつけない
ユーザの自動登録への対処
アカウントの自動登録の被害から守る
- CAPTCHAによる自動登録対策
パスワード変更
パスワード変更の機能的な注意点としては以下がある
- 現在のパスワードを確認する
- パスワード変更時にはメールでその旨を通知する
また、パスワード変更機能に生じやすい全弱性としては以下がある
- SQLインジェクション脆弱性
- CSRF脆弱性
現在のパスワードを確認すること
パスワード変更に先立ち、現在のパスワードを入力してもらい照合します(再認証)。これにより、セッションハイジャックされた状態で第三者がパスワードを変更することを防止できる
パスワード変更時のメール通知
パスワード変更のような重要な処理がなされた場合、その旨を利用者にメール通知する。これにより、第三者が不正にパスワード変更した場合でも、早期に利用者が気づくことができる
パスワード変更機能に生じやすい脆弱性
SQLインジェクション脆弱性
CSRF脆弱性
パスワード変更画面にSQLインジェクション脆弱性があると、以下の脅威が考えられる
- 再認証を回避してパスワードを変更
- 別ユーザのパスワード変更
- 前ユーザのパスワードを一斉に変更
メールアドレスの変更
メールアドレスの不正変更に悪用される典型的な手口には以下がある
- セッションハイジャック
- CSRF攻撃
- SQLインジェクション攻撃
メールアドレス変更に必要な機能的対策
メールアドレス変更に必要な機能的な対策としては以下
- 新規メールアドレスに対する受信確認
- 再認証
- メール通知
パスワードリマインダ
管理者向けパスワードリマインダ
利用者からの問い合わせでパスワードをリセットする場合、以下の順序で運用を行う。
1.問い合わせを受け付け、利用者の本人確認を行う
2.管理者がパスワードをリセットし、利用者に仮パスワードを伝える
3.利用者は仮パスワードでログインし、直ちにパスワードを変更する
利用者向けパスワードリマインダ
利用者向けパスワードリマインダはパスワードを忘れた利用者が自らパスワードを調べる、あるいはリセットするための機能、以下の内容がある
本人確認の方法
- ユーザー登録時に「秘密の質問と答え」を登録してもらい、パスワードリマインダを使う場合に秘密の質問に回答してもらう
- 登録されたメールアドレスのメールを受け取れることで本人確認する
パスワード通知方法
- 現在のパスワードをメールで通知する
- パスワード変更画面のURLをメールで通知する
- 仮パスワードを発行してメールで通知する
- パスワード変更画面に直接遷移する
アカウントの停止
アカウントを停止すべき状況の例が以下
- 利用者本人からの依頼(PCを盗まれた、スマートフォンを落とした、心当たりのないパスワード変更通知メールを受け取った、など)
- 不正アクセスを受けている場合
アカウントの削除
アカウントの削除は、通常取り消しできない処理なので、本人の意思確認とCSRF脆弱性対策を目的として、パスワードの確認(再認証)を要求すると良い
これ以外にもアカウント削除処理に混入しやすい脆弱性として、SQLインジェクション脆弱性がある
アカウント管理のまとめ
各機能に共通する注意点は以下
- ユーザが入力したメールアドレスは必ず受信確認を行う
- 重要な処理に際して再確認
- 重要な処理のメール通知
またアカウント管理に共通して混入しやすい脆弱性は以下
- SQLインジェクション脆弱性
- CSRF脆弱性
- メールヘッダ・インジェクション脆弱性
認可
認可とは
認可とは、認証された利用者に対して権限を与えること。権限の例を以下に
- 認証された利用者のみに許可された機能(退会処理、送金(振り込み)、新規ユーザ作成(管理者として)など)
- 認証された利用者のみに許可された情報の閲覧(非公開の利用者自身の個人情報、非公開の他利用者の利用者個人情報(管理者として)、非公開の掲示板の内容、webメールなど)
- 認証された利用者のみに許可された編集操作(利用者本人の設定変更(パスワード、プロフィール、画面設定など)、他利用者の設定変更(管理者として)、Webメールからのメール送信など)
認可不備の典型例
- 情報リソースのIDを変更すると権限外の情報が参照できる
- メニューの表示・非表示のみで制御している
- hiddenパラメータやクッキーに権限情報を保持している
ログ出力
ログ出力の目的
アプリケーションのログがセキュリティ上も重要である理由は以下
- 攻撃や事故の予兆をログから把握し、早期に対策するため
- 攻撃や事故の事後調査のため
- アプリケーションの運用調査のため
ログの種類
webアプリケーションに関係するログには以下がある
- webサーバーのログ
- アプリケーションログ
- データベースログ
アプリケーションが生成するログは以下
- エラーログ
文字通りアプリケーションの様々なエラーを記録するもの。エラーログは攻撃の検出に役立つ場合もあり、SQLインジェクション攻撃やディレクトリ・トラバーサル攻撃などの試行中には、SQLのエラーやファイルオープンのエラーが発生しやすくなる。 - アクセスログ
webアプリケーションの情報閲覧や機能の利用記録としてのログ - デバッグログ
文字通りデバッグ用のログ。デバッグログは開発環境やテスト環境で取得すべきもので、本番環境では取得するべきではない
ログ出力の要件
ログに記録すべきイベント
- ログイン・ログアウト(失敗も含む)
- アカウントロック
- ユーザ登録・削除
- パスワード変更
- 重要情報の参照
- 重要な操作(物品の購入、送金、メール送信など)
ログの出力項目
- アクセス日時
- リモートIPアドレス
- ユーザID
- アクセス対象(URL、ページ番号、スクリプトIDなど)
- 操作内容(閲覧、変更、削除など)
- 操作対象(リソースIDなど)
- 操作結果(成功あるいは失敗、処理件数など)
6章 文字コードとセキュリティ
文字コードとセキュリティの概要
文字コードに関する設定やプログラミングを正しく行わなければ、脆弱性の原因になり得る
文字コードとは、以下の2つの概念をあわえたもの
- 文字集合
- 文字エンコーディング(文字符号化方式)
文字集合
文字集合とは、その名の示すように文字を集めたもの
アルファベット大文字、数字は文字集合の例
文字コードによる脆弱性の発生要因まとめ
文字コードの起因する脆弱性は以下
- 文字エンコーディングとして不正なバイト列による脆弱性
- 文字エンコーディングの扱いの不備による脆弱性
- 文字集合の変更に起因する脆弱性
文字コードを正しく扱うために
文字コードを正しく扱うためには、以下の4つのポイントがある
- アプリケーション全体を通して文字集合を統一する
- 入力時に不正な文字エンコーディングをエラーにする
- 処理の中で文字エンコーディングを正しく扱う
- 出力時に文字エンコーディングを正しく指定する
8章 Webサイトの安全性を高めるために
webサーバーへの攻撃経路と対策
webサイトのセキュリティを強化するためには、アプリケーションの脆弱性を解消するだけでは不十分で、webサーバーなど基盤ソフトウェアの安全性を高めることも重要
基盤ソフトウェアの脆弱性をついた攻撃
OSやwebサーバーなどの基盤ソフトウェアの脆弱性をついた攻撃により、不正侵入を受ける場合がある、webサーバーなどにクロスサイト・スクリプティング(XSS)脆弱性があり、受動的な攻撃により利用者が被害を受ける場合もある
不正ログイン
webサーバーの管理に用いるソフトウェアに対するパスワード攻撃は頻繁に行われている、攻撃者は、サーバーに対してポートスキャンという手法で有効なポート番号や稼働しているサービスを調べ、管理用ソフトウェアが有効になっていれば、辞書攻撃などによりパスワードを調べる
対策
webサーバーへの攻撃の対策としては以下が重要
- サービス提供に不要なソフトウェアは稼働させない
- 脆弱性の対処をタイムリーに行う
- 一般公開する必要のないポートやサービスはアクセス制限する
- 認証の強度を高める
なりすまし対策
ネットワーク的ななりすまし手口
ネットワーク的ななりすましの手口のうち、攻撃事例が報道されたのは以下の手法
- DNSに対する攻撃
- ARPスプーフィング
DNSに対する攻撃
- DNSサーバーに対する攻撃によりDNSの設定内容を書き換える
- DNSキャッシュポイズニング攻撃
- 失効したドメインを第三者が購入して悪用
ARPスプーフィング
ARPスプーフィングとは、ARPの偽応答を返すことで、IPアドレスを偽装する手法
フィッシング
フィッシングとは、正規サイトにそっくりな入力画面を用意してメールなどで利用者を誘導し、IDとパスワードや個人情報などを入力させて盗み取る手法
webサイトのなりすまし対策
- ネットワーク的な対策
- SSL/TLSの導入
- 確認しやすいドメインの採用
盗聴・改ざん対策
- 無線LANの盗聴・改ざん
- ミラーポートの悪用
- プロキシサーバーの悪用
- 偽のDHCPサーバー
- ARPスプーフィングとDNSキャッシュポイズニング
マルウェア対策
webサイトのマルウェア対策とは
webサイトのマルウェア対策には以下の2つの意味がある
- webサーバーがマルウェア感染しないこと
1.情報漏洩
2.サイト改ざん
3.不正な機能実行
4.他サイトへの攻撃(踏み台) - webサイトを通じてマルウェアを公開しないこと
webサイトを閲覧した利用者のPCがマルウェアに感染する
webサーバーのマルウェア対策の概要
- サーバーの脆弱性対処をタイムリーに行う
- 出所不明なプログラムをサーバーに持ち込まない
- サーバー上では運営に直接関係のない操作をしない
- サーバーにUSBメモリなどの外部メディアを装着しない
- webサーバーのネットワークを執務スペースのLANと切り離す
- サーバーに接続するクライアントPCにウイルス対策ソフトを導入してパターンファイルを最新に保つ
- windows update などによりクライアントPCに最新のセキュリティパッチを導入する
終わりに
今までセキュリティなどを意識しないでサービス作っていた部分があったけれど、どの部分が狙われるのか、どのように対処していいかが鮮明に書かれていたのでそれをRails作るときにも意識してコードを書けそう
参考
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践