セキュリティ
HTTPS とセキュリティヘッダー、CSP、公開ディレクトリに置かないファイル、XSS を防ぐ DOM 操作、フォームの入力検証とスパム対策
Web サイトの制作で必要になる、基本的なセキュリティ対策をまとめています。 外部ライブラリの選び方と CDN から読み込むときの SRI はライブラリの利用、機密情報の管理は GitHub 権限・セキュリティを参照してください。
HTTPS
すべてのページを HTTPS で配信し、HTTP へのアクセスは HTTPS へ 301 リダイレクトします。
ページ内で読み込む画像・スクリプト・フォームの送信先も、すべて https:// にします。HTTPS のページから HTTP のリソースを読み込むと、ブラウザがブロックするか警告を表示します(混在コンテンツ)。
セキュリティヘッダー
サーバーやホスティングサービスの設定で、次のレスポンスヘッダーを付けます。
| ヘッダー | 値の例 | 防ぐもの |
|---|---|---|
Strict-Transport-Security |
max-age=31536000 |
HTTP での接続。一度アクセスしたブラウザは、以後 HTTPS でしか接続しない |
X-Content-Type-Options |
nosniff |
ブラウザがファイルの種類を推測し、画像などをスクリプトとして実行すること |
Content-Security-Policy |
frame-ancestors 'self' |
他のサイトの iframe にページを埋め込み、ボタンを押させる攻撃(クリックジャッキング) |
Referrer-Policy |
strict-origin-when-cross-origin |
外部サイトへの遷移時に、ページの URL(パスやクエリ)が送られること |
Permissions-Policy |
camera=(), microphone=(), geolocation=() |
サイトで使わないブラウザの機能を、埋め込んだ外部スクリプトが使うこと |
設定例
Cloudflare Pages では、ビルド成果物に _headers ファイルを置きます。
/*
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
Content-Security-Policy: frame-ancestors 'self'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Apache のレンタルサーバーでは、.htaccess に記述します。
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000"
Header always set X-Content-Type-Options "nosniff"
Header always set Content-Security-Policy "frame-ancestors 'self'"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
CSP(Content Security Policy)
CSP は、ページが読み込めるスクリプトや画像の読み込み元を制限し、XSS の被害を抑える仕組みです。 ただし、計測タグや埋め込みなど外部のスクリプトを多く使うサイトでは、許可する読み込み元の管理が難しくなります。案件の状況に応じて、次の段階で導入してください。
- 最低限: 上記の
frame-ancestors 'self'に加え、object-src 'none'とbase-uri 'self'を指定する。サイトの動作にほぼ影響しない - 読み込み元の制限:
script-srcなどで読み込み元を列挙する。まずContent-Security-Policy-Report-Onlyヘッダーで違反をブラウザの Console に出すだけにして、必要な読み込み元を洗い出してからContent-Security-Policyに切り替える
Content-Security-Policy: frame-ancestors 'self'; object-src 'none'; base-uri 'self'
公開ディレクトリに置かないファイル
次のファイルは、サーバーの公開ディレクトリにアップロードしないでください。URL を推測されると、誰でもダウンロードできます。
.envなどの環境変数ファイル.gitディレクトリ- データベースのバックアップ(
.sqlなど) - ビルド前のソースファイルや、作業用のファイル(
.psd、.figの書き出し元など)
デプロイをビルド成果物だけに限定すると、これらのファイルが混ざるのを防げます。
また、Vite では VITE_ で始まる環境変数がビルド後の JavaScript に埋め込まれ、誰でも読める状態になります。API キーなどの秘密の値には VITE_ を付けないでください。
DOM 操作での XSS 対策
ユーザーの入力や URL のパラメータ、外部の API から受け取った文字列を、HTML として解釈させないでください。
// ❌ 文字列に含まれるタグやスクリプトが実行される
message.innerHTML = params.get("name");
// ✅ 文字列をそのままテキストとして表示する
message.textContent = params.get("name");
innerHTML・outerHTML・insertAdjacentHTML() に渡してよいのは、コードに直接書いた固定の文字列だけです。
外部から受け取った URL を href や src に設定する場合は、javascript: などのスキームが使われていないことを確認してください。
const url = new URL(input, location.href);
if (url.protocol === "https:" || url.protocol === "http:") {
link.href = url.href;
}
フォーム
- 入力検証はサーバー側で行う: HTML の
requiredや JavaScript での検証は、入力を助けるためのものです。ブラウザを通さずに送信することもできるため、サーバー側でも必ず検証してください。 - スパム対策をする: Cloudflare Turnstile や reCAPTCHA などのボット対策を入れます。
- CSRF 対策をする: CMS やフレームワークが用意しているトークンの仕組み(WordPress の nonce など)を使います。
- メール送信は実績のある仕組みを使う: 自作の
mail()関数の呼び出しは、ヘッダーインジェクションなどの脆弱性を作りやすいため避け、CMS のフォームプラグインやフォーム送信サービスを使います。 - 個人情報を扱うフォーム: プライバシーポリシーへのリンクを送信ボタンの近くに置きます。