ウェブセキュリティの強化:ヘッダーとCookieの設定方法
はじめに
Webアプリケーションのセキュリティは、常に進化する脅威に対抗するためには不可欠です。
本記事では、サーバー応答のセキュリティを向上させるためのヘッダーの設定方法と、
Cookieの安全な扱い方について解説します。
サンプルコードはPHPになります。
またこれから扱う内容は検証ツールを開いてネットワークタブのレスポンスヘッダーの話しになります。
セキュリティヘッダーの設定
X-Content-Type-Options
このヘッダーをnosniff
に設定することで、ブラウザはMIMEタイプのスニッフィングを無効にし、指定されたContent-Type
のみを扱うようになります。これは、悪意あるスクリプトが異なるMIMEタイプとして解釈され実行されることを防ぐために重要です。
スニッフィングとは:ブラウザがファイルの種類を自動で判断すること
$response->headers->set('X-Content-Type-Options', 'nosniff');
Content-Security-Policy (CSP)
CSPを設定する際には、どのリソースが信頼されているかをブラウザに指示するためのポリシーを定義します。以下は一例になります。
- default-src 'self':デフォルトで、同一のオリジンからのリソースのみを許可します。
- img-src 'self' data::画像は同一オリジン、またはdata URIからのもののみ許可します。
- script-src 'self' 'unsafe-inline' https::スクリプトは同一オリジン、HTTPSプロトコルを使用する外部サイト、またはインラインスクリプトを許可します。
- style-src 'self' 'unsafe-inline':スタイルシートは同一オリジンまたはインラインスタイルを許可します。
これらの設定は、特定のニーズに合わせて調整することが可能です。例えば、外部のAPIやCDNからスクリプトやスタイルシートを読み込む必要がある場合は、それらのソースを明示的に許可リストに追加することが重要です。
PHPでのCSP設定例
以下のPHPコードは、上記のCSPルールを設定する方法を示しています:
$response->headers->set('Content-Security-Policy', "default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline';");
XSS攻撃の容易化
unsafe-inline
を使用すると、悪意のあるユーザーがWebページにインラインスクリプトを注入し、他のユーザーがそのページを閲覧する際に実行されることで、セッションハイジャックやデータの漏洩が発生する可能性があります。これは、サイトにとって重大なセキュリティリスクを意味します。
コンテンツの整合性
unsafe-inline
は、サイトが意図しないスクリプトやスタイルの実行を許可してしまうため、コンテンツの整合性を損なう可能性があります。これにより、ユーザーエクスペリエンスが低下するだけでなく、悪意のあるコンテンツの実行が可能になります。
より安全な代替策
安全性を高めるためには、'unsafe-inline'
オプションを避け、以下のような方策を採用することが推奨されます:
Content Security Policy Nonces(CSPノンス)
スクリプトやスタイルにユニークなノンス(一回限りの数値)を付与し、CSPポリシーでそのノンスを指定することで、承認されたコンテンツのみが実行されるようにします。これは、特定のリソースがセキュリティポリシーに準拠していることを保証します。
外部ファイルの利用
インラインではなく、外部JavaScriptファイルやCSSファイルを使用し、これらのリソースに対して整合性の検証(Subresource Integrity, SRI)を行うことで、より安全にリソースを管理します。SRIは、外部リソースが改ざんされていないことを確認するために役立ちます。
CSPを設定する際には、これらの代替策を検討し、アプリケーションのセキュリティを確保しつつ、利便性とのバランスを取ることが重要です。
その他のセキュリティヘッダー
-
Cache-Control:
no-store
を設定することで、ブラウザにキャッシュを全く保持させないようにします。これは、センシティブな情報がクライアント側に残るのを防ぎます。
$response->headers->set('Cache-Control', 'no-store');
X-Frame-Options
X-Frame-OptionsをDENY
に設定することで、サイトがフレーム内で表示されることを完全に禁止します。これは、クリックジャッキング攻撃から保護するために役立ちます。
$response->headers->set('X-Frame-Options', 'DENY');
Strict-Transport-Security
Strict-Transport-Securityを設定することで、HTTPSを強制し、中間者攻撃によるデータの傍受を防ぎます。max-age
パラメータはブラウザがHTTPS接続のみを使う期間を秒数で指定し、includeSubDomains
はすべてのサブドメインにポリシーを適用し、preload
はブラウザのプリロードリストにサイトを含めることを意味します。
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Strict-Transport-Security#strict_transport_security_%E3%81%AE%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%89
https://www.proactivedefense.jp/blog/blog-vulnerability-assessment/post-2179#index_id7
サーバーの情報
サーバーの詳細情報を隠すことで、攻撃者に対する手がかりを減らすことができます。
// nginx.conf
nginx: server_tokens off; // バージョン情報の公開を停止します。
PHP: expose_php = off //PHPのバージョン情報を隠します。
安全なCookieの設定
Secure属性
この属性が設定されているCookieは、HTTPSを通じてのみ送信されます。これにより、データが暗号化され、中間者によるデータの傍受や改ざんを防ぐことができます。HTTP接続では、このCookieは送信されません。
HttpOnly属性
HttpOnly属性を持つCookieは、JavaScriptを通じてアクセスできないようになります。これにより、クロスサイトスクリプティング(XSS)攻撃によるCookieの盗難を防ぐことができます。JavaScriptがCookieの値を読み取れなくなるため、攻撃者がユーザーのセッションIDなどを盗み出すのが難しくなります。
SameSite属性
SameSite属性は、Cookieがクロスサイトのリクエストと共に送信されることを制限します。この属性には主に以下の設定があります:
- Strict: この設定では、Cookieは同一サイトのリクエストでのみ送信されます。ユーザーがリンクをクリックして新しいタブやウィンドウでページが開かれた場合でも、他のサイトからのリクエストには含まれません。
- Lax: ほとんどのケースでStrictと同じ挙動をしますが、ユーザーが外部サイトから直接リンクをクリックしてナビゲートした場合などに、Cookieを送信することがあります。
- None: すべてのクロスサイトのリクエストにCookieを含めるためには、この設定を使用し、Secure属性も設定する必要があります。
setcookie(
'user_session', // Cookieの名前
$sessionValue, // Cookieの値
[
'expires' => time() + 60 * 60 * 24 * 30, // 有効期限
'path' => '/', // パス
'domain' => '', // ドメイン
'secure' => true, // Secureフラグ
'httponly' => true, // HttpOnlyフラグ
'samesite' => 'Strict' // SameSite属性
]
);
まとめ
大元のレスポンスに設定するだけなので簡単に実装はできます。 Laravelならcookiek系の設定はconfig/session.phpで設定が可能です。
余談ですがこの実装でsessionはサーバーサイドで cookieはフロントでデータを扱うものだと知りました。今更過ぎる、、、
CSPについてですが javascriptとかcssってphpのファイルに書けたりするじゃないですか。 scriptタグとかstyleタグとか あれこのCSPの設定すると全部エラーになるんですよ。
そもそもCSPはXSS(クロスサイトスクリプティング)攻撃からウェブアプリケーションを守りやすくなるものなのですが、 自分のサイトのJSファイルだけを読み込む設定をすることで 外部のJSファイルを弾くことができます。 外部のJSライブラリを使うときはscript-src等にその読み込むライブラリのURLを指定して読ませる設定をします。
ちなみに外部のライブラリのコードがインラインでコーディングしてたみたいで このCSPの設定が出来ずに外部ライブラリ使えないって事もありました、、
ファイル分けるのって見やすいだけじゃなくて セキュリティ的にも利点があるのでちゃんとコード書こうという気持ちを強くさせてくれました。