セキュリティに関する考慮事項
Webアプリケーションは通常、あらゆる種類のセキュリティ問題に直面しており、すべてを正しく行うことは非常に困難です。 Flaskはこれらの問題のいくつかを解決しようとしますが、自分で対処しなければならないことがいくつかあります。
クロスサイトスクリプティング(XSS)
クロスサイトスクリプティングは、任意のHTML(およびJavaScript)をWebサイトのコンテキストに挿入するという概念です。 これを修正するには、開発者はテキストを適切にエスケープして、任意のHTMLタグを含めないようにする必要があります。 詳細については、クロスサイトスクリプティングに関するウィキペディアの記事を参照してください。
Flaskは、特に明記されていない限り、すべての値を自動的にエスケープするようにJinja2を構成します。 これにより、テンプレートで発生するすべてのXSSの問題が除外されますが、注意が必要な場所は他にもあります。
- Jinja2の助けを借りずにHTMLを生成する
- ユーザーから送信されたデータに対して
Markup
を呼び出す - アップロードされたファイルからHTMLを送信する場合は、絶対に行わないでください。この問題を防ぐには、
Content-Disposition: attachment
ヘッダーを使用してください。 - アップロードされたファイルからテキストファイルを送信します。 一部のブラウザは、最初の数バイトに基づいてコンテンツタイプの推測を使用しているため、ユーザーはブラウザをだましてHTMLを実行できます。
非常に重要なもう1つのことは、引用符で囲まれていない属性です。 Jinja2はHTMLをエスケープすることでXSSの問題からユーザーを保護できますが、属性インジェクションによるXSSから保護できないことが1つあります。 この可能性のある攻撃ベクトルに対抗するには、属性でJinja式を使用する場合は、必ず二重引用符または一重引用符で属性を引用してください。
<input value="{{ value }}">
なぜこれが必要なのですか? そうしないと、攻撃者がカスタムJavaScriptハンドラーを簡単に挿入する可能性があるためです。 たとえば、攻撃者は次のHTML + JavaScriptを挿入する可能性があります。
onmouseover=alert(document.cookie)
その後、ユーザーがマウスを入力の上に移動すると、アラートウィンドウにCookieが表示されます。 ただし、Cookieをユーザーに表示する代わりに、優れた攻撃者が他のJavaScriptコードを実行する可能性もあります。 CSSインジェクションと組み合わせて、攻撃者は要素をページ全体に入力させることもできるため、ユーザーはページ上の任意の場所にマウスを置くだけで攻撃をトリガーできます。
Jinjaのエスケープが保護しないXSS問題の1つのクラスがあります。 a
タグのhref
属性には、 javascript: URIを含めることができます。これは、適切に保護されていない場合、クリックするとブラウザが実行します。
<a href="{{ value }}">click here</a>
<a href="javascript:alert('unsafe');">click here</a>
これを防ぐには、コンテンツセキュリティポリシー(CSP)応答ヘッダーを設定する必要があります。
クロスサイトリクエストフォージェリ(CSRF)
もう1つの大きな問題はCSRFです。 これは非常に複雑なトピックであり、ここでは詳しく説明しません。それが何であるか、および理論的にそれを防ぐ方法についてのみ説明します。
認証情報がCookieに保存されている場合は、暗黙的な状態管理があります。 「ログイン中」の状態はCookieによって制御され、そのCookieはリクエストごとにページに送信されます。 残念ながら、これにはサードパーティのサイトによってトリガーされたリクエストが含まれます。 それを覚えていない場合、ソーシャルエンジニアリングでアプリケーションのユーザーをだまして、知らないうちに愚かなことをする人がいるかもしれません。
POST
リクエストを送信すると、ユーザーのプロファイルが削除される特定のURLがあるとします(たとえば、http://example.com/user/delete
)。 攻撃者がJavaScriptを使用してそのページにPOSTリクエストを送信するページを作成した場合、攻撃者は一部のユーザーをだましてそのページをロードするだけで、プロファイルが削除されてしまいます。
何百万人もの同時ユーザーでFacebookを運営していて、誰かが小さな子猫の画像へのリンクを送信するとします。 ユーザーがそのページにアクセスすると、ふわふわの猫の画像を見ているときにプロフィールが削除されます。
どうすればそれを防ぐことができますか? 基本的に、サーバー上のコンテンツを変更するリクエストごとに、ワンタイムトークンを使用して、それをCookie に保存し、もフォームデータとともに送信する必要があります。 サーバーでデータを再度受信した後、2つのトークンを比較して、それらが等しいことを確認する必要があります。
なぜFlaskはあなたのためにそれをしないのですか? これが発生する理想的な場所は、Flaskには存在しないフォーム検証フレームワークです。
JSONセキュリティ
Flask 0.10以前では、jsonify()
はトップレベルの配列をJSONにシリアル化しませんでした。 これは、ECMAScript4のセキュリティの脆弱性が原因でした。
ECMAScript 5はこの脆弱性を解消したため、非常に古いブラウザーのみが依然として脆弱です。 これらのブラウザにはすべてその他のより深刻な脆弱性があるため、この動作が変更され、jsonify()
がアレイのシリアル化をサポートするようになりました。
セキュリティヘッダー
ブラウザは、セキュリティを制御するためにさまざまな応答ヘッダーを認識します。 アプリケーションで使用するために、以下の各ヘッダーを確認することをお勧めします。 Flask-Talisman 拡張機能を使用して、HTTPSとセキュリティヘッダーを管理できます。
HTTP Strict Transport Security(HSTS)
すべてのHTTPリクエストをHTTPSに変換するようにブラウザに指示し、man-in-the-middle(MITM)攻撃を防ぎます。
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
コンテンツセキュリティポリシー(CSP)
さまざまなタイプのリソースをどこからロードできるかをブラウザに通知します。 このヘッダーは可能な限り使用する必要がありますが、サイトの正しいポリシーを定義するためにいくつかの作業が必要です。 非常に厳格なポリシーは次のとおりです。
response.headers['Content-Security-Policy'] = "default-src 'self'"
- https://csp.withgoogle.com/docs/index.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
X-Content-Type-Options
ブラウザーに、応答コンテンツタイプを検出しようとするのではなく、それを尊重するように強制します。これは、クロスサイトスクリプティング(XSS)攻撃を生成するために悪用される可能性があります。
response.headers['X-Content-Type-Options'] = 'nosniff'
Xフレーム-オプション
外部サイトがサイトをiframe
に埋め込むのを防ぎます。 これにより、外枠のクリックが目に見えない形でページの要素のクリックに変換される可能性があるクラスの攻撃を防ぎます。 これは「クリックジャッキング」とも呼ばれます。
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
X-XSS-保護
リクエストにJavaScriptのようなものが含まれていて、レスポンスに同じデータが含まれている場合、ブラウザはページを読み込まないことで、反映されたXSS攻撃を防止しようとします。
response.headers['X-XSS-Protection'] = '1; mode=block'
HTTP公開鍵ピンニング(HPKP)
これは、MITM攻撃を防ぐために、特定の証明書キーのみを使用してサーバーで認証するようにブラウザーに指示します。
警告
キーを誤って設定またはアップグレードすると元に戻すのが非常に難しいため、これを有効にするときは注意してください。