セキュリティガイド
Play フレームワークは、セキュリティを念頭に置いて設計されています - しかし、開発者が Play フレームワークを誤って使い、セキュリティホールを開けてしまうことを防ぐのは不可能です。このガイドはウェブアプリケーションにおけるセキュリティ上の一般的な問題と、Play アプリケーション でどのようにしてそれらを避けるかについて説明します。
セッション
ユーザに関連する情報、特にログイン状態を保つ必要があることが、よくあります。セッションがなければ、ユーザは、リクエスト毎に認証照明を送信しなければなりません。
セッションは、これら: ユーザのブラウザに保存される、ユーザをウェブサイトで特定するクッキーのセット、ウェブアプリケーションが保存先にデータ層よりもむしろセッションを選ぶかもしれない、例えば言語情報のために存在します。
秘密鍵は… 秘密のまま
セッションは、署名はされていますが暗号化はされていないキー/値のハッシュです。これは、秘密鍵が安全である限り、第三者がセッションを捏造できないことを意味します。
秘密鍵は conf/application.conf
に保存されます。これを自分だけのものとして保持することは非常に重要です: 公開されたリポジトリにこれをコミットしてはいけませんし、他の誰かによって書かれたアプリケーションをインストールするときには、秘密鍵を自分自身の物に変更しなければなりません。これは、“play secret” コマンドで行うことができます。
重要なデータは保存しない
とは言え、セッションは暗号化されていないので、セッションに重要なデータを保存するべきではありません。LAN や Wi-Fi 上の接続を盗聴することで、これらのデータをユーザクッキー上に見ることができます。
セッションはクッキーの中に保存され、クッキーは 4KB に制限されます。この制限に加え、保存できるのは文字列のみです。
クロスサイトスクリプティング
クロスサイトスクリプティングはウェブアプリケーションでもっとも一般的な脆弱性の 1 つです。XSS は、アプリケーションが提供するフォームを使用することで悪意ある JavaScript をウェブページに挿し込むことで成立します。
誰でもコメントできるブログシステム書いているとしましょう。この HTML ページに訪問者が書き込む内容を盲目的に受け入れる場合、このサイトは攻撃者に対して開かれています。攻撃は以下のように行われます:
- 訪問者にポップアップを表示します
- 攻撃者によって制御されたサイトに訪問者をリダイレクトします
- 現在の訪問者にのみが閲覧できるべきであった情報が盗まれ、攻撃者のサイトに送信されます
したがって、これらの攻撃からアプリケーションを保護するのは非常に重要です。
Play のテンプレートエンジンは自動的に文字列をエスケープします。エスケープしていないHTMLを入れたければ、文字列でのJava拡張 raw() を使ってください。しかしユーザーの入力した文字列には、最初にサニタイズされているかの確認が必要になります。
ユーザ入力をサニタイズするときは、常に (安全でないタグを禁止し、それ以外を許可する) ブラックリスト方式よりも、(安全なタグのみを許可する) ホワイトリスト方式を優先してください。
SQL インジェクション
SQL インジェクションは、開発者が意図しない SQL クエリを実行するユーザ入力を使用することで成立する脆弱性です。データを破壊したり、または現在のユーザにとって見えるべきでないデータにアクセスするために使用されます。
高レベルの “find” メソッドを使用する場合、SQL インジェクションに対応するべきです。手動でクエリを作成する場合、@+@ で文字列を連結するのではなく、 ?
プレースホルダーを使用するように注意するべきです。
これは良いです:
createQuery("SELECT * from Stuff WHERE type= ?1").setParameter(1, theType);
これは良くありません:
createQuery("SELECT * from Stuff WHERE type=" + theType);
クロスサイトリクエストフォージェリ
CSRF は、ウェブアプリケーションにおいて真の問題になる場合があります:
この攻撃手法は、ユーザが認証されていると信じている web アプリケーションにアクセスするページに悪意あるコードかリンクを含めることで実行されます。この web アプリケーションのセッションがタイムアウトされていない場合、攻撃者は認証されていない命令を実行できる場合があります。
この攻撃を防ぐために最初にすることは、GET と POST メソッドを適切に使用することです。これは、アプリケーションの状態を変更に使用されるのは POST メソッドだけであるべきということを意味します。
POST リクエストをセキュアで重要なアクションとして適切に保証する唯一の方法は、認証トークンを発行することです。現在の Play にはこれを扱う組み込みのヘルパがあります:
- 新しい
checkAuthenticity()
メソッドがコントローラで利用可能であり、これはリクエストパラメータ中に有効な認証トークンが存在するかどうかチェックし、何かが正しくない場合は、認証不可のレスポンスを送信します。 session.getAuthenticityToken()
は、現在のセッションにおいてのみ有効な認証トークンを生成します。#{authenticityToken/}
は、どのようなフォームにも加えることができる hidden 入力フィールドを作成します。
例えば、以下のようにすると:
public static destroyMyAccount() {
checkAuthenticity();
...
}
適切な認証トークンを含むフォームから呼ばれた場合にのみ動作します:
<form method="post" action="/account/destroy">
#{authenticityToken /}
<input type="submit" value="destroy my account">
#{/form}
POST リクエストで, Play の form タグ で信頼性トークンが自動的に生成されます。:
#{form @destroyMyAccount()}
<input type="submit" value="destroy my account">
#{/form}
もちろん、コントローラ階層におけるすべてのアクションを保護したい場合は、これを 事前フィルタ をcallする checkAuthenticity()
メソッドとして追加することができます。
考察を続けます
次: Play モジュール