Webアプリケーション 脆弱性チェックリスト



追加(2019/1/29)
PeingにおけるTwitter APIトークン流出を受けて、更新しました
"Peing - 質問箱 -"に脆弱性、なぜか利用者のTwitter APIトークンがソースにべた書きされていた | 90の日記 | スラド


追記(2019/1/17)
2019/1/15にOWASP JAPANより
Webシステム/Webアプリケーションセキュリティ要件書
がVer.3.0にアップデートされました。

今回の更新ではチェックリストも公開されていますので、是非そちらもご覧ください。

この記事必要無いとか言わない。


はじめに

セキュリティ対策、してますか?

セキュリティ対策はあらゆる攻撃を想定しなければならず、問題発生時の損害が非常に大きい場合も多く、リリース時には完璧(にできるだけ近い形)にしておくことが求められます。

また、フレームワークやライブラリなどを利用する際、どのようにセキュリティが担保されているか理解することも重要です。
開発チームに途中から加わった際、セキュリティが全く考慮されていないアプリケーションに出会うことがあるかもしれません。
(残念ながら「動作しているだけ」のアプリケーションは実在します)

備忘録として、Webアプリケーション開発におけるセキュリティについてチェックすべき点を洗い出してみました。
対応の平易さに応じてレベル分けしています。レベルが低い程簡単に対応できるので、低い方から順に潰していくのがおすすめです。

不足しているチェック項目や認識の間違いなどありましたら、コメントからご指摘お願いします。

※サーバー関連のチェック項目(ログ管理・メール関連・他諸々)については一つの記事にまとめると量的に読みづらくなりそうなので省きました。
機会があれば別の記事としてまとめます。

レベル0

名もなき脆弱性。またの名をクソコード。
局所的には即修正可能です。
修正箇所が多い場合はタイミングを見て一気に対応します。

公開ページ上にシステムエラーメッセージ

長い開発期間によってシステムエラーに慣れてしまっていませんか?
公開サイトでシステムエラーが表示されるのは異常事態です。
システムメッセージの中にはプログラム構造を把握するための情報が含まれる場合がありますので、Webサーバーの設定でエラーメッセージを表示しないようにしましょう。

不要な情報のHTMLコメントアウト

テスト環境がない場合( ! )、テンプレートファイル上で確認用のデータ出力されていたことがありました。

index.php
<!-- <?php var_dump($data); ?> -->

ブラウザの「ページのソースを表示」で中身が丸わかりとなるのですぐに消しましょう。

パスワードを入力するinputタグがtype="text"

驚くべきことに、高度なハッカーはあなたの肩越しに入力内容をのぞき見することが可能です。
type="password"
に変更して入力内容を隠蔽しましょう。
PASS:********

レベル1

アプリケーションのロジックによっては修正に時間がかかる場合があります。
設計時に気をつけていればなんてことはない......と思っていると痛い目を見るかも。
油断大敵、煩悩退散。

パスワードが平文保持

データベースや設定ファイルを見られてしまった場合にパスワードが漏洩しないよう、ハッシュ化しましょう。
また、暗号化はNGです。「ハッシュ化」は不可逆変換ですが「暗号化」は可逆変換です。
暗号化した場合、暗号化のルールが読み取られると元のパスワードが判明して(復号されて)しまいます。
※ハッシュ化さえすれば元のパスワードは分からない、というとそうでもありません。詳しくは下記記事が解りやすかったです。
2018年のパスワードハッシュ - Qiita

例えば、「password」という文字列について各種アルゴリズムでハッシュ値を事前に記録しておけば、このデータは「password」のハッシュ値だな、と読み取られてしまいます(こういった入力とハッシュ値の相関を記録した表を「レインボーテーブル」と呼びます)。

ユーザーの入力するパスワードの脆弱性を弱めるため、入力されたパスワードには「salt」というランダムな文字列を付加してハッシュ化するという手法があります。こうすることで、「password」ではなく「*****password*****」というような文字列をハッシュ化するため、レインボーテーブルから元の入力値を逆算することが難しくなります。
また、ユーザーごとにsaltを異なるものにすることで、同じパスワードでも違うハッシュ値となるため、パスワード漏洩の拡大を防ぐという役割も持ちます。

ただし、認証の際には入力値と登録されているハッシュ値が同等かどうかを評価する必要があるため、登録時に利用したsaltはセットで記録しておくのがいいでしょう。

2018年5月、Twitterのパスワードが内部システムのログファイルに平文で保存されていたというニュースがありました。
最終的にハッシュ化されていればOK、ではなく、平文のパスワードがどこにも残らないように注意が必要です。

キャッシュの制御不備

キャッシュの制御不備が存在すると、サーバー上にキャッシュされた特定の個人情報が別ユーザーのブラウザに表示されます。
不備自体を避けるのが一番ですが、個人情報を含む重要なページについてはキャッシュを保存しないようにすることもできます。
HTTPレスポンスヘッダーフィールドに
「Cache-Control: no-store」
と指定することで、任意ページのキャッシュを防ぐことができます。

※制御不備に対するロジックを含めてレベル1としています。

アプリケーション・バッファオーバーフロー

大容量のファイルを送りつけられるとシステムバッファが許容量をオーバーしてシステムダウンや予期せぬ動作を起こす可能性があります。
ファイルのアップロード機能がある場合はきちんとファイル内容をチェックしましょう。
What is this?

XXE(XML外部エンティティ参照)

XXEはXMLの「DTD(ドックタイプ宣言)」処理を利用した外部エンティティ参照にまつわる脆弱性を指します。
外部エンティティ参照により、サーバー内(XMLから見た外部)の情報を取得することが可能となります。

攻撃の具体例として、「XMLをアップロードし、アップロードされたXMLのデータを解析・出力する機能」においてDTD処理が有効になっている場合、攻撃者はXMLファイルに

warui.xml
<!DOCTYPE foo [
<!ENTITY pass SYSTEM "/etc/passwd">
]>

というタグを埋め込みアップロードすることで、「/etc/passwd」の中身を出力させることが可能になります。

古いXMLプロセッサではXXE対策がなされていないものがあります。
また、外部エンティティをデフォルトでは参照しないXMLプロセッサでも、デフォルトで行わないだけで処理によっては参照可能、ということもありますので、XMLプロセッサごとの仕様に注意してください。

各種プロセッサでのXXE対策はOWASPからまとめられています。
XML External Entity (XXE) Prevention Cheat Sheet - OWASP

レベル2

レベル2ではデータの取扱い・検証が主となります。
このあたりからは状況に合わせて適切な対策方法を自分で導出する必要があります。

インジェクション

「インジェクション」は日本語で「注入」を意味します。
一般的に、悪意のある文字列が「注入」される脆弱性を「〜インジェクション」と呼びます。

攻撃者はWebブラウザからの入力値をコマンドやクエリに見せかけることで、サーバ内の機密情報の取得や削除、改ざんなどを行います。

対策としては、XSSと同様に入力された値を正しくバリデーション・エスケープして処理系に渡すことが重要です。エスケープの方法はインタープリターごとに合わせた方法で行ってください。
Injection Prevention Cheat Sheet - OWASP
SQL Injection Prevention Cheat Sheet - OWASP
Injection Prevention Cheat Sheet in Java - OWASP
Query Parameterization Cheat Sheet - OWASP

また、SQLインジェクション対策としてはORマッパーのプリペアードステートメントやプレースホルダを利用することで対策を行えますが、それだけでは完璧な対策とは言えません。
状況に合わせて適切なバリデーションやエスケープを組み合わせることでできる限りの堅牢さを構築する必要があります。
完全なSQLインジェクション対策 – yohgaki's blog

XSS(クロスサイトスクリプティング )

XSSは動的Webページの脆弱性を突いてスクリプトを悪意のあるスクリプトを実行させる攻撃手法です。

例えばJavaScriptにおいて入力されたURLをもとに文字列を表示する処理を行う場合、対策を行わなければ以下のような結果になります。

<!--
http://脆弱性のあるサイト/脆弱性のあるページ?q=<script>location.href = "kanekuresagisagi.com"</script>にアクセスした場合
-->
<div>
  <script>location.href = "kanekuresagisagi.com"</script>
</div>

この方法により、不適切なリンクにアクセスした場合は「kanekuresagisagi.com」へリダイレクトされてしまいます。
このようなDOM操作を利用したXSSをDOM Based(DOMベース)XSSと呼びます。
他にも、サーバーへ任意の結果を返すスクリプトを送りつけられるReflected(反射型)XSSや、スクリプトをサーバーへ格納させられるStored(格納型)XSSなどがあります。

このような脆弱性を避けるため、データを正しくエスケープする必要があります。
状況別のXSSの適切なエスケープ方法がOWASPよりまとめられています。
XSS (Cross Site Scripting) Prevention Cheat Sheet - OWASP

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

CSRFは悪意のあるスクリプトを埋め込んだ自作のWebページに誘導し、他者のWebページにおいて強制的に意図的なリクエストを行わせる攻撃方法です。

XSSと名前が被っていてややこしいですが、対策方法は異なります。
基本的にはフォーム入力処理を受け付ける際に、正規のフォームから入力されたかどうかを判別できるようにすることが重要です。

例えば、フォームからサーバーへリクエストを送るWebページを用意する際に、攻撃者の推測できないhiddenパラメータを用意することで正規の画面遷移を用いたフォーム利用かどうかを判断することで、CSRFの対策を行うことができます。

2018年現在では、CSRF対策を行えるフレームワークも多く存在しているので、その機能を利用するのもいいかもしれません。

実例では2005年にmixiの脆弱性を突き、強制的に定型文の日記を作成させられるCSRF攻撃があったそうです(通称「はまちちゃん事件」)。
実例をモチーフにした漫画があったので貼っておきます。
アクセスは自己責任で
第1回 HTTPのしくみを復習しよう:[はまちちゃんのセキュリティ講座]ここがキミの脆弱なところ…!|gihyo.jp … 技術評論社

column未指定でのSELECT(追記:2019/1/29)

2019年1月28日、PeingにおいてユーザーのTwitter APIトークンがソースにべた書きされて流出してしまった問題が発覚しました。
この問題について原因は公開されていませんが、は元開発者の方が「トークンをuser TABLEか何かに保存して、そのままcolumn未指定でSELECTしたことにより、余計な非公開情報まで取得してしまっていたのでは」といった予測をTweetされていました。
(結構な飛び火があったようで、既に関連のTweetは削除されています)

規模が大きくなるとどうしてもテーブルの情報を把握できなくなることがあるかと思いますので、要求するデータ量を抑制するという意味でも、SELECT時のカラム指定は欠かさないようにしましょう。

参考

全般

Japan - OWASP
Webアプリケーションの脆弱性まとめ | 脆弱性 | CyberSecurityTIMES
安全なウェブサイトの作り方:IPA 独立行政法人 情報処理推進機構

XML外部実体参照(XXE)

PHPプログラマのためのXXE入門 | 徳丸浩の日記
PHPとXML eXternal Entity(XXE)対策 – yohgaki's blog

インジェクション

SQLインジェクション攻撃への対策|脆弱性を悪用する仕組みと具体例
完全なSQLインジェクション対策 – yohgaki's blog

クロスサイトスクリプティング (XSS)

クロスサイトスクリプティング(XSS)
クロスサイトスクリプティング対策 ホンキのキホン - 葉っぱ日記

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

第3回 Webセキュリティのおさらい その3 CSRF・オープンリダイレクト・クリックジャッキング:JavaScriptセキュリティの基礎知識|gihyo.jp … 技術評論社