銀行員からのRailsエンジニア

銀行員からのRailsエンジニア

銀行員から転身したサービス作りが大好きなRailsエンジニアのブログです。個人で開発したサービスをいくつか運営しており、今も新しいサービスを開発しています。転職して日々感じていること、個人開発サービス運営のことなどを等身大で書いていきます。

【技術書メモ】体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 〜毎週アウトプットチャレンジ④〜

毎週 1冊技術書を読んでブログでアウトプットするチャレンジの第4弾ですーー!

今回は、体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践 を読みました。

本書はWebアプリケーションの脆弱性に関する名著であり、2018/6/20に第2版が発売されました。

少し長くなってしまいましたが、頑張ってまとめましたので是非読んでみてください。

f:id:ysk_pro:20180813150939j:plain

1 Webアプリケーションの脆弱性とは

- 脆弱性とは悪用できるバグ

- 脆弱性が生まれる理由

  - バグ

  - チェック機能の不足

 

3 Webセキュリティの基礎

3-1 HTTPとセッション管理

- 秘密情報をPOSTで送信すべき理由(GETのリスク)

  - URL上に指定されたパラメータがReferer経由で外部に漏洩する

  - URL上に指定されたパラメータがアクセスログに残る

  - パラメータ付きのURLを利用者がソーシャルネットワークなどで共有してしまう

- hiddenパラメータは利用者は書き換えることができるが、第三者からの書き換えに対しては堅牢

- クッキーは少量のデータをブラウザ側で覚えておけるものだが、アプリケーションデータを保持する目的では次の理由から行われない

  - クッキーが保持できる値の個数や文字列長に制限がある

  - クッキーの値は利用者本人には参照・変更できるので、秘密情報の格納に向かない

- クッキーには整理番号としてセッションIDを格納し、実際の値はサーバー側に管理する方法がよく取られる

- セッションIDに求められる要件は次の通り

  - 第三者がセッションIDを推測できない

  - 第三者からセッションIDを強制されない

  - 第三者にセッションIDが漏洩しない

- セッションIDは自作せず、Webアプリケーション開発ツールで提供されるセッションIDを利用すべき

- Secure属性をつけたクッキーはHttps通信の場合のみサーバーに送信される

- HttpOnly属性は、JavaScriptからアクセスできないクッキーを設定するもの

 

3-2 受動的攻撃と同一オリジンポリシー

- 受動的攻撃とは、攻撃者がサーバーを直接攻撃するのではなく、Webサイトの利用者に罠を仕掛けることにより、罠を閲覧したユーザを通じてアプリケーションを攻撃する手法

- 同一オリジンポリシーとは、JavaScriptなどのクライアントスクリプトからサイトをまたがったアクセスを禁止するセキュリティ上の制限

 

4 Webアプリケーションの機能別に見るセキュリティバグ

4-1 Webアプリケーションの機能と脆弱性の対応

- 脆弱性には処理に起因するものと出力に起因するものがあり、出力に起因するものはインジェクション系脆弱性と呼ばれる

 

4-2 入力処理とセキュリティ

- Webアプリケーションの入り口では、入力の文字エンコーディング検証と変換、入力値のチェックを実施する。これらはセキュリティに対する根本的な対策ではないが、プラットフォームやアプリケーションに潜在的脆弱性があった場合のセーフティネットとして作用する 

 

4-3 表示処理に伴う問題

- XSS脆弱性の対策としては、表示の際にHTMLで特殊な意味を持つ記号文字(メタ文字)をエスケープすることが有効

- XSSに対する保険的対策

  - X-XSS-Protection レスポンスヘッダの使用:ブラウザのセキュリティ機能を有効にする

  - クッキーにHttpOnly属性を付与する

 

4-4 SQL呼び出しに伴う脆弱性

- SQLインジェクションは、データベース内の任意のデータを漏洩し、書き換えることができるので非常に危険

- SQLインジェクションの確実な対策は静的プレースホルダを利用してSQLを呼び出すこと

  - SQL文中の「?」がプレースホルダで、変数や式など可変のパラメータの場所に埋め込んでおくもの

  - 静的プレースホルダは値のバインド(? に値を割り当てること)をデータベースエンジン側で行う。プレースホルダの状態でSQL文がコンパイルされるため、後からSQL文が変更される可能性はない

  - 動的プレースホルダはアプリケーション側のライブラリ内でパラメータをバインドしてデータベースエンジンに送る方式

 

4-5 重要な処理の際に混入する脆弱性

- クロスサイト・リクエストフォージェリ(CSRF)は、重要な処理の前に利用者のリクエストであることを確認する処理が抜けている場合に、罠のサイトを閲覧しただけで利用者のブラウザから勝手に重要な処理を実行されられる脆弱性

- CSRFの対策は、利用者の意図したリクエストであることの確認で、以下の方法がある

  - トークン埋め込み 〜重要な処理のページに第三者が知り得ないトークンを要求することによって利用者を識別する

  - パスワード再入力

  - Referer確認

- クリックジャッキングはiframe要素とCSSを巧妙に利用することで、透明にした攻撃対象ページと罠のサイトを重ね合わせ、利用者が気づかないうちに攻撃対象サイトでのうリックを誘導する攻撃手法

- クリックジャッキングは、主要ブラウザで採用されているX-Frame-Optionsを有効にすることで対策ができる 

 

4-6 セッション管理の不備

- セッションの固定化攻撃の対策としては、認証後にセッションIDを変更する方法がある 

 

4-7 リダイレクト処理にまつわる脆弱性

- パラメータにより指定した任意のドメインにリダイレクトできる脆弱性をオープンリダイレクト脆弱性と呼び、フィッシングに悪用される

- オープンリダイレクト脆弱性の対策としては、リダイレクト先のURLを固定にすればよい

- HTTPヘッダ・インジェクションの原因は外部から指定された改行をそのまま出力することで、HTTPヘッダ出力部分を自分で作らずにヘッダ出力用のライブラリやAPIを利用することで対策ができる 

 

4-8 クッキー出力にまつわる脆弱性

- クッキーにSecure属性をつけていないと、平文で送信されて盗聴される可能性がある 

 

4-9 メール送信の問題

- メールのメッセージヘッダに外部から改行を追加されることがメールヘッダ・インジェクションの原因となり、対策にはメール送信に専用のAPIやライブラリを用いることが有効 

 

4-10 ファイルアクセスにまつわる問題

- ディレクトリ・トラバーサル脆弱性とは、外部からパラメータの形でサーバー上のファイル名を指定できるWebアプリケーションでファイル名のチェックが不十分な場合にアプリケーションの意図しないファイルが閲覧・改ざんされてしまう脆弱性

- ディレクトリ・トラバーサル攻撃の対策としては、外部からファイル名が指定できる仕様を避けることが有効 

 

4-10 OSコマンド呼び出しの際に発生する脆弱性

- OSコマンド・インジェクションの対策としては、OSコマンドを呼び出さない実装方法を選択することが有効 

 

4-11 ファイルアップロードにまつわる問題

- Webアプリケーションのアップロード機能に対して大量のデータを送信することで、
Webサイトに過大な負荷をかけるDoS攻撃があり、対策にはアップロードファイルの容量制限が有効 

 

4-12 インクルードにまつわる問題

- require・ includeなどでソースの一部を外部から指定できる場合、アプリケーションが意図しないファイルを指定することにより脆弱性が生まれることがあり、対策としてはインクルードするパス名に外部からのパラメータを含めないことが有効

 

4-16 Web API実装における脆弱性

- APIにおいてJSON文字列生成時のエスケープ処理に不備があると、意図しないJavaScriptJSONデータに混入する脆弱性があり、対策としては信頼できるライブラリを用いてJSONを生成することが有効

 

5 代表的なセキュリティ機能

5-1 認証

- パスワードを桁数や文字種類などで厳しくチェックしすぎると、かえって安全なパスワードをつける利用者のモチベーションを下げてしまうことがある

- オンラインでのブルートフォース攻撃への対抗策としてはアカウントロックが有効。10回程度パスワードを間違えたらアカウントロックがかかり、ロックから30分経過した場合は自動的に解除される、というような実装がされることが多い

 

5-2 アカウント管理

- メールアドレスの受信確認は、①メールにトークン付きURLを添付してそのURLから処理を継続する、②メールアドレスを入力した後にトークン(確認番号)入力画面に遷移し、トークンはメール送信される、の2パターンある。Aがよく使われるが、メール記載のURLを利用者に閲覧させるという習慣はフィッシング対策上よくないので、筆者はBを推奨している

- 外部からの自動操作により大量に新規ユーザを作成されることを防ぐため、「私はロボットではありません」にチェックしてもらう等のCAPTCHAがよく利用される

- パスワードを変更する際は、現在のパスワードを照合する。これによりセッションハイジャックされた状態で第三者がパスワードを変更することを防止できる

- メールアドレス変更時のメール通知は新旧両方のメールアドレスに対して行う。これは第三者に不正にメールアドレスを変更された場合に正当なユーザが気づけるようにするため 

 

5-3 認可

- 認可制御の実装がきちんとされていないと、情報リソースのURLを知っているだけで認証なしで情報が閲覧できてしまう

- 認可制御の不備の原因の多くは画面の制御のみで認可制御を実装しているつもりになっていることであり、操作に先立ってこの機能を実行してよいユーザであるかを確認する必要がある

- ユーザ情報は、外部から書き換えできないセッション変数に保持する。書き換えができるクッキーやhiddenパラメータなどに保持しない 

 

5-4 ログ出力

- ログに記録すべきイベントは多すぎても少なすぎてもダメで、ログの使用目的から決定すべき。一般的には以下の認証・アカウント管理・重要な情報の操作をログ出力することが多い

  - ログイン・ログアウト(失敗も含む)

  - アカウントロック

  - ユーザ登録・削除

  - パスワード変更

  - 重要情報の参照

  - 重要な操作(物品の購入、送金、メール送信など)

- ログの出力項目は、4W1H(いつ、誰が、どこで、何を、どのように)に従った以下の項目を取得する

  - アクセス日時

  - リモートIPアドレス

  - ユーザID

  - アクセス対象(URL、ページ番号、スクリプトIDなど)

  - 操作内容(閲覧、変更、削除など)

  - 操作対象(リソースIDなど)

  - 操作結果(成功あるいは失敗、処理件数など)

- ログの出力先にはデータベースやファイルがよく用いられるが、ログの保護という観点からはログ専用のサーバーを用意することが望ましい 

 

6 文字コードとセキュリティ

- 文字コードの扱いに問題があると文字列処理にバグが生じ、脆弱性の原因になる

- 対策としてはアプリケーション全体の文字エンコーディングUTF-8で統一することが推奨されている 

 

7 脆弱性診断入門

- 開発時に脆弱性を作り込まないように気をつけていても脆弱性は混入してしまう可能性が高い。プログラミングにおいて機能を実装したら必ずテストをするのと同じように、脆弱性がないこともテストで確認する必要があり、それが脆弱性診断である

 

8 Webサイトの安全性を高めるために 

- Webサーバーがマルウェアに感染する経路は、メールが9割

- Webサーバーマルウェア対策としては、サーバーの脆弱性対処をタイムリーに行うことや、クライアントPCに最新のセキュリティパッチを導入することが有効

 

9 安全なWebアプリケーションのための開発にマネジメント

- 安全なアプリケーション開発のために費用対効果が高いのは開発標準(セキュリティガイドライン)の整備

- 開発標準に記載すべき重要項目は以下の通り

  - 脆弱性毎の対処方法

  - 認証、セッション管理、ログ出力などの実装方法

  - 各フェーズでのレビューとテストの方法(いつ、誰が、何を、どうやって)

  - 公開判定基準(誰が、いつ、どの基準で許可するか)

- セキュリティ機能は最終的にテストにより要件を満たすことを確認する必要がある。セキュリティテスト(脆弱性検査)の方法には、専門家に依頼する、専用ツールで診断する、などの方法がある

 

おわりに

ここまで読んでいただきありがとうございます。

Webアプリケーションの脆弱性については、実務では必須の知識なので(僕の会社でも現在進行形でこの本の勉強会を毎週しています)ご興味ある方は是非読んでみることをおすすめしますー!

来週も頑張ります!