2011年に発売された書籍の第二版が2018年6月に発売された。
- Webアプリケーションの脆弱性とは
- 実習環境のインストール
- Webセキュリティの基礎
- Webアプリケーションの機能別にみるセキュリティバグ
- Webアプリケーションの機能と脆弱性の対応
- 入力処理とセキュリティ
- 表示処理に伴う問題
- SQL呼び出しに伴う脆弱性
- 「重要な処理】の際に混入する脆弱性
- セッション管理の不備
- リダイレクト処理にまつわる脆弱性
- クッキー出力にまつわる脆弱性
- メール送信の問題
- ファイルアクセスにまつわる問題
- OSコマンド呼び出しの際に発生する脆弱性
- ファイルアップロードにまつわる問題
- インクルードにまつわる問題
- 構造化データの読み込みにまつわる問題
- 共有資源やキャッシュに関する問題
- Web API実装における脆弱性
- JavaScriptの問題
- 代表的なセキュリティ機能
- 認証
- アカウント管理
- 認可
- ログ出力
- 文字コードとセキュリティ
- 脆弱性診断入門
- Nmapによるポートスキャン
- OpenVASによるプラットフォーム脆弱性診断
- OWASP ZAPによる自動脆弱性スキャン
- OWASP ZAPによる手動脆弱性診断
- RIPSによるソースコード診断
- Webサイトの安全性を高めるために
- なりすまし対策
- 盗聴・改ざん対策
- マルウェア対策
- 安全なWebアプリケーションのための開発マネジメント
脆弱性とは「悪用できるバグ」のこと。
Webアプリケーションにとって脆弱性は身近なものである。
脆弱性を悪用されることによる損失が結構でかい
- 経済的損失
- 利用者が受ける金銭的損失の補填
- 詫び石
- Webサイト停止に寄る機会損失
- 脆弱性による損害を受けた取引先からの損害賠償
- 法的要求
- 利用者が回復不能なダメージを受けることが多い
- Webサイト利用者に嘘をつくことになる
- 「このサイトはセキュリティを考えてないので自己責任でね」とはいえない
- 攻撃インフラに加担することになる
- バグに寄るもの
- SQLインジェクション、XSS
- チェック機能の不足によるもの
- ディレクトリトラバーサルとか
この本では上記2つを明確に分けている。
セキュリティの担保にはセキュリティのバグを潰すだけでは不十分。
通信経路が暗号化されていない状態→バグじゃないけど機能として不足
このような積極的な安全性強化を「セキュリティ機能、セキュリティ要件」と呼ぶ。
非機能要件の一つとして数えられる。
IPAが公開している冊子
OWASPという国際的なWebアプリケーションセキュリティの課題解決を目的とするオープンコミュニティ
VirtualBoxの仮想アプリケーションが用意されていて、体系的に学ぶことができる。
httpリクエストをいじれる
FireFoxの拡張
リクエストを別portに転送できる
リクエストメセージは
- メソッド
- URL
- プロトコルバージョン から構成される。
レスポンスメッセージは
- ステータスライン
- ヘッダ
- 1行の空行
- ボディ(本文) から構成される。
http/2はバイナリになってる。
HTTP/1.1 200 OK
プロトコールバージョン、ステータスコード、テキストフレーズに分かれる。
よく見るあれ。テキストフレーズもステータスコードに付随する。
- Content-Length
- ボディ部のバイト数
- Content-Type
- MINEタイプというリソースの種類を指定。
| MINEタイプ | 意味 |
|---|---|
| text/plain | テキスト |
| text/html | HTML文書 |
| application/xml | XML文書 |
| application/json | json |
| text/css | CSS |
| image/gif | GIF画像 |
| application/pdf | PDF文書 |
| application/x-www-form-urlencoded | name=valueを&でつなげたリクエスト形式 |
とかとか。ブラウザがこれを見てボディがなんなのか判断する。
- GETメソッドは参照のみに用いる
- GEtTメソッドには副作用がない
- 秘密情報の送信にはPOSTを用いる
機密情報をPOSTで投げなければいけない理由、つまるところGETで機密情報を投げては行けない理由は
- URLに指定指定されたパラメータがReferer経由で外部に出る
- URLに指定されたパラメータがアクセスログに残る(POSTの本文はまず残らない)
- URLのパラメータがブラウザのアドレスバーに表示され他人に覗かれる。
- パラメータがついたURLをそのままSNSで共有できちゃう
とうとう。2つめについては情報安全確保支援士の午後IIにも出てきたね。
hiddenパラメータについて
Webページの確認画面はpostボタンしかない場合が多い。
でもこのボタンを押したときに送信されるデータはそのページ内に保持されていないといけない。
このとき、inputタグにhiddenパラメータを入れて、非表示の入力欄を設ける。
入力画面から確認画面の遷移時に入力内容を非表示の入力欄に入力してやるとボタン押したときにちゃんとpostできるわけ。
でも、このタグは書き換えができる。
単純なブラウザ認証方式
アクセスすると401:unauthorizedを返す。
ブラウザはuserとpasswordの入力を要求する。
入力して返すとブラウザはAuthorization: Basic dXNlcjE6cGFzczE=を返す。
後ろの文字列はuserとpasswordを":"でつないでbase64エンコードしたもの。
この認証は認証状態が一切保持されない。認証が必要な場合はページにアクセスするたびにuserとpasswordの入力を要求される。
流石に面倒なので、ブラウザがBasic認証後に同じディレクトリ内で遷移するときにAuthorizationヘッダーを勝手にくっつけてくれる。
これによってページ遷移したあとでも認証ダイアログが表示されないってわけ。
セッションを使用する場合バックエンドサーバーはレスポンスのSet-CookieヘッダにセッションIDを付加する。
ブラウザはこのセッションIDをCookieに保存する。
POSTメソッド送信時にはpostのリクエストボディと一緒にCookieヘッダを付加してセッションIDをもたせる。
- 第三者がセッションIDを推測できないこと
- 第三者からセッションIDを強制されないこと
- 第三者にセッションIDが漏洩しないこと
推測ができると、第三者が認証後のセッションI�Dを乗っ取って何でも出来ちゃう
推測されないようにするためには、セッションIDを長くして、乱数の質を上げる。
アプリケーションレベルの話をすると、セッションIDの管理を自作しない!!
強制されると、第三者がセッションIDだけ取得して正規のユーザにセッションIDを渡して認証させることで何でも出来ちゃう(セッションIDの固定化攻撃)
強制されないようにするためには、認証後に新しいセッションIDを発行してやる。
漏洩しちゃうと、他人になりすましができる。 漏洩の原因には
- クッキー発行の属性に不備がある
- ネットワーク的にセッションIDが盗聴される環境にある
- クロスサイトスクリプティングなどのアプリケーションの脆弱性がある
- プラットフォームの脆弱性がある
- セッションIDをURLに保持している(Refereヘッダから漏洩する)
とかとかがある。
クッキーを送信するドメインを指定できる。
デフォルトだと、発行したサーバー以外ではクッキーの読み書きができない。
複数のサーバーでクッキーの読み書きを行いたい場合に設定する。
だいたいミスって漏れる。デフォルトの状態が一番強固なので、変更しない。
JavaScriptからのクッキーの読み書きを禁止する。
これも支援士の問題で出てきたねー
https通信の場合にのみクッキーをサーバーに送信する。 これも支援士の問題にでてきたねー
Webアプリケーションに対する攻撃は以下の二種類に区別される
- 能動的攻撃
- サーバにダイレクトアタック
- 受動的攻撃
- サーバに罠を仕掛け、罠にかかった正規ユーザを通してサーバを攻撃する
最近は正規サイトに罠を仕掛ける受動的攻撃が主流
- 罠サイトに誘導する手間がいらない
- 正規利用者の数が多いので被害拡大が早い
- 利用者の個人情報が取れたりする
手口としては
- FTPなどのパスワードを入手して書き換えちゃう
- Webサーバーの脆弱性をついて書き換えちゃう
- SQLインジェクション攻撃でコンテンツを書き換えちゃう
- SNSなどの利用者が投稿できるサイト機能のクロスサイトスクリプティングを利用する。
プログラムのできることを制限する環境のこと。
androidアプリケーションとかのOS機能に介入するやつとかWebサービスがOAuth認証するときのレベルのあれ。
JavaScriptは異なるドメインに対してオブジェクトを渡すことができない。
同一オリジンである条件は
- URLのFQDNが一致している。ホストが同じ
- スキーム(プロトコル)が同じ
- ポート番号が同じ
書籍の例では同一オリジンである場合とホスト名が異なる場合で同一オリジンポリシーが正しく動いていることを確認している。
ちなみに、Ajaxで使用するXMLHttpRequestについてはCORSという規格があり、これによって同一オリジンでなくても相手の許可があれば通信できる。
異なるドメインのアクセスが許可されている要素は以下のとおり
けど、ドメインが異なるページが2枚ある場合、そのドキュメントには互いにアクセスできない
他ドメインの画像は見れる。
他ドメインのスクリプトは実行できる。CDN
scriptと同様
Cross-Origin Resource Sharingの略 フロントエンドで他ドメインのコンテンツを表示させる(Ajax)ときとかに通信ができる仕組み。
通常はexample.jpからJavascriptでapi.example.netのapiを叩いても取得できない。
シンプルなリクエストで通信を可能にするためには、Access-Control-Allow-Origin [対象ドメイン]ヘッダをレスポンスに追加する。
シンプルなリクエストだとこれだけで送れる。 シンプルなリクエストとは
- GET,POST,NEADメソッドのいずれか
- setRequestHEaderには以下のヘッダのみ設定されている
- Accept
- Accept-Language
- Content-Language
- Content-Type
- Content-Typeヘッダhが以下のいずれか
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
シンプルじゃないリクエストはプリフライトリクエストと言われる。
リクエストなので、レスポンスは関係ない。
レスポンスのcontent-typeがapplication/jsonだとしても、リクエストタイプのcontent-typeが空ならそれはシンプルなリクエストになる。
XMLHttpRequest呼び出しの際に以下のリクエストを投げる。(プリフライトリクエスト)
メソッドがOPTIONSになっている。
OPTIONS http://api.example.net/33/33-004b.php HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://example.jp
Connection: keep-alive
Host: api.example.net
APIサーバーはこのリクエストに対してレスポンスヘッダを付加して応答する。
Access-Control-Allow-Origin: http://example.jp
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 1728000
このレスポンスがきてようやくPOSTを送れる
クロスオリジンアクセスではHTTP認証やクッキーなどの認証に使用されるリクエストヘッダは送信されない。
が、下記設定を行うことで対応ができる。
var req = new XMLHttpRequest();
req.open('GET', 'http://api.example.net/33/33-006.php');
+ req.withCredentials = true;XMLHttpRequstオブジェクトのwithCredentialsプロパティをtrueにする。
レスポンスヘッダにAccess-Control-Allow-Credentials: trueを付加する。