フリーキーズ | 独学プログラミング

Security Headers入門!X-Frame-OptionsやX-Content-Type-Optionsでサイトを守る基礎知識

リンドくん

リンドくん

たなべ先生、Webサイトのセキュリティって難しそうですね...何から勉強すればいいんですか?

たなべ

たなべ

Security Headers(セキュリティヘッダ)という仕組みを理解するだけで、多くの攻撃からサイトを守ることができるんだよ。
これは初心者でも実践できる重要な対策なんだ。

Webアプリケーションを開発していると、セキュリティという言葉をよく耳にするのではないでしょうか。
しかし、具体的に何をすれば良いのか分からないという方も多いはずです。

実は、HTTPレスポンスヘッダに適切な設定を追加するだけで、多くのセキュリティリスクを軽減できるのです。
これがSecurity Headers(セキュリティヘッダ)と呼ばれる仕組みです。

本記事では、プログラミング学習者やWeb開発初心者の方に向けて、Security Headersの基礎知識から実践的な設定方法まで、わかりやすく解説していきます。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

Security Headersとは何か?

リンドくん

リンドくん

そもそも「ヘッダ」って何ですか?普通のHTMLとは違うんですか?

たなべ

たなべ

ヘッダは、ブラウザとサーバがやり取りする際の「指示書」のようなものなんだ。
HTMLはページの内容だけど、ヘッダはブラウザに「このページをどう扱うべきか」を伝える役割があるんだよ。

HTTPヘッダの基本的な仕組み

Webサイトにアクセスするとき、ブラウザとWebサーバの間では様々な情報がやり取りされています。
その中でHTTPヘッダは、ページのコンテンツ(HTML)とは別に送信される「メタ情報」です。

HTTPヘッダには以下のような情報が含まれます。

  • コンテンツの種類 - HTMLなのか、画像なのか、JSONなのか
  • 文字エンコーディング - UTF-8などの文字コード情報
  • キャッシュの制御 - ブラウザにファイルを保存させるかどうか
  • セキュリティ設定 - 今回解説するSecurity Headers

これらのヘッダ情報は、ブラウザの開発者ツールで確認できます。
ChromeやFirefoxのデベロッパーツールを開き、「Network」タブから任意のリクエストを選択すると、送受信されたヘッダ情報を見ることができます。

Security Headersの役割

Security Headersは、ブラウザに対してセキュリティ上の制約や振る舞いを指示するHTTPヘッダです。
これにより、以下のような攻撃から保護できます。

  • クリックジャッキング - 透明なiframeを使ってユーザーを騙す攻撃
  • XSS(クロスサイトスクリプティング) - 悪意あるスクリプトを埋め込む攻撃
  • MIME Type Sniffing - ファイルの種類を誤認させる攻撃
  • 中間者攻撃 - 通信を傍受・改ざんする攻撃

つまり、Security Headersはサーバ側からブラウザに「このページは安全にこう扱ってね」と指示を出す仕組みなのです。

なぜSecurity Headersが重要なのか

現代のWebアプリケーションは、様々な脅威にさらされています。
攻撃者は常に新しい手法を開発しており、開発者は防御策を講じる必要があります。

Security Headersの優れた点は、以下のような特徴があることです。

  • 実装が比較的簡単 - サーバ設定やコードに数行追加するだけ
  • 既存コードへの影響が少ない - ページの内容を変更せずに適用可能
  • 幅広い攻撃を防げる - 複数の脅威に対して効果的
  • 標準化されている - ブラウザベンダーが広くサポート

セキュリティ対策というと難しそうですが、Security Headersは初心者でも導入しやすい防御策なのです。

主要なSecurity Headersの種類と役割

リンドくん

リンドくん

Security Headersっていろんな種類があるんですか?全部覚えないといけないんでしょうか...

たなべ

たなべ

安心して!まずは基本的な4つのヘッダを理解すれば十分なんだ。それぞれが異なる攻撃から守ってくれるから、一つずつ見ていこう。

X-Frame-Options - クリックジャッキング対策

X-Frame-Optionsは、あなたのWebページが他のサイトのiframe内に埋め込まれるのを防ぐヘッダです。

攻撃者は、あなたのサイトを透明なiframeとして悪意あるサイトに埋め込み、ユーザーに気づかれないようにクリックさせる「クリックジャッキング」という攻撃を行うことがあります。
X-Frame-Optionsを設定することで、この攻撃を防ぐことができます。

設定値の種類

X-Frame-Options: DENY
  • すべてのサイトでのiframe埋め込みを拒否します
X-Frame-Options: SAMEORIGIN
  • 同一オリジン(同じドメイン)からのみ埋め込みを許可します
X-Frame-Options: ALLOW-FROM https://____.com
  • 特定のドメインからのみ埋め込みを許可します(非推奨)

実際には、多くの場合はDENYまたはSAMEORIGINを使用します
自社サイト内でiframeを使う必要がある場合はSAMEORIGIN、それ以外はDENYを選択すると良いでしょう。

X-Content-Type-Options - MIMEタイプスニッフィング対策

X-Content-Type-Optionsは、ブラウザがファイルの種類を勝手に推測するのを防ぐヘッダです。

ブラウザは通常、サーバが送信する「Content-Type」ヘッダを見てファイルの種類を判断します。
しかし、古いブラウザはファイルの内容から種類を「推測」してしまうことがあり、これが攻撃に悪用される可能性があります。

設定方法

X-Content-Type-Options: nosniff

この設定により、ブラウザはサーバが指定したContent-Typeを厳密に守るようになります。
例えば、画像としてアップロードされたファイルがJavaScriptコードを含んでいても、それをスクリプトとして実行することを防げます。

Content-Security-Policy(CSP) - XSS対策の切り札

Content-Security-Policy(CSP)は、最も強力で柔軟性の高いSecurity Headerです。
このヘッダを使うことで、ページ内でどのリソース(スクリプト、スタイル、画像など)を読み込めるかを細かく制御できます。

基本的な設定例

Content-Security-Policy: default-src 'self'; script-src 'self' https://____.com; style-src 'self' 'unsafe-inline'

この設定の意味は以下の通りです。

  • default-src 'self' - デフォルトでは同一オリジンからのみリソースを許可
  • script-src 'self' https://____.com - スクリプトは自サイトと特定のCDNからのみ許可
  • style-src 'self' 'unsafe-inline' - スタイルは自サイトとインラインスタイルを許可

CSPは非常に強力ですが、設定が複雑になりがちです。
最初は緩めの設定から始めて、徐々に厳しくしていくアプローチをおすすめします。

Strict-Transport-Security(HSTS) - HTTPS通信の強制

Strict-Transport-Security(HSTS)は、ブラウザに対して「このサイトは常にHTTPSでアクセスしてね」と指示するヘッダです。

設定例

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

この設定の意味は以下の通りです。

  • max-age=31536000 - 1年間(秒単位)、この設定を記憶
  • includeSubDomains - サブドメインにも適用
  • preload - ブラウザのHSTSプリロードリストに登録可能

重要な点として、HSTSを設定する前に、サイト全体が正しくHTTPSで動作することを確認してください。
設定後は指定期間中、HTTPでのアクセスが完全にブロックされるためです。

Security Headersの設定方法

リンドくん

リンドくん

実際にどうやって設定すればいいんですか?プログラミング言語によって違ったりするんでしょうか?

たなべ

たなべ

設定方法は大きく分けてサーバ設定で行う方法アプリケーションコードで行う方法の2つがあるんだ。それぞれ見ていこう。

Webサーバでの設定(Apache)

Apacheサーバを使用している場合、.htaccessファイルまたはhttpd.confに以下のように記述します。

# X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"

# X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"

# Content-Security-Policy
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://____.com; style-src 'self' 'unsafe-inline';"

# Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

この設定により、すべてのレスポンスに自動的にSecurity Headersが追加されます。

Webサーバでの設定(Nginx)

Nginxサーバを使用している場合、サーバ設定ファイル(通常は/etc/nginx/sites-available/内)に以下を追加します。

server {
    # X-Frame-Options
    add_header X-Frame-Options "SAMEORIGIN" always;
    
    # X-Content-Type-Options
    add_header X-Content-Type-Options "nosniff" always;
    
    # Content-Security-Policy
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://____.com; style-src 'self' 'unsafe-inline';" always;
    
    # Strict-Transport-Security
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}

Node.js(Express)での設定

Node.jsのExpressフレームワークを使用している場合、ミドルウェアとして設定できます。
helmetというパッケージを使うと簡単です。

const express = require('express');
const helmet = require('helmet');

const app = express();

// helmetを使った基本設定
app.use(helmet());

// より詳細な設定も可能
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "https://____.com"],
      styleSrc: ["'self'", "'unsafe-inline'"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  }
}));

app.listen(3000);

helmetパッケージは、Security Headersの設定を非常に簡単にしてくれる優れたツールです。

Pythonアプリケーション(Flask)での設定

Flaskアプリケーションでは、デコレータやafter_requestフックを使用して設定できます。

from flask import Flask, make_response

app = Flask(__name__)

@app.after_request
def set_security_headers(response):
    response.headers['X-Frame-Options'] = 'SAMEORIGIN'
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self' https://____.com"
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
    return response

@app.route('/')
def index():
    return 'Hello, Secure World!'

if __name__ == '__main__':
    app.run()

この設定により、すべてのレスポンスに自動的にSecurity Headersが追加されます。

PHPでの設定

PHPアプリケーションでは、header()関数を使用してレスポンスヘッダを設定できます。

<?php
// Security Headersの設定
header("X-Frame-Options: SAMEORIGIN");
header("X-Content-Type-Options: nosniff");
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://____.com");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains; preload");
?>

<!DOCTYPE html>
<html>
<head>
    <title>Secure Page</title>
</head>
<body>
    <h1>Hello, Secure World!</h1>
</body>
</html>

重要な点として、header()関数は必ず出力(echoやHTML)の前に呼び出す必要があります。

Security Headersの確認とテスト方法

リンドくん

リンドくん

設定したあと、ちゃんと動いているか確認する方法はありますか?

たなべ

たなべ

もちろん!いくつか便利な方法があるよ。ブラウザの開発者ツールを使う方法と、専門的なテストツールを使う方法があるんだ。

ブラウザの開発者ツールでの確認

最も手軽な確認方法は、ブラウザの開発者ツールを使うことです。

手順(Chrome/Edgeの場合)

  1. 確認したいページを開く
  2. F12キーを押して開発者ツールを開く
  3. 「Network」タブを選択
  4. ページをリロード(F5キー)
  5. 一番上のドキュメント(通常はHTMLファイル)をクリック
  6. 「Headers」セクションの「Response Headers」を確認

ここで設定したSecurity Headersが表示されていれば、正しく設定できています。

オンラインツールでのセキュリティスキャン

より詳細な確認には、以下のようなオンラインツールが便利です。

Security Headers

このサイトにURLを入力するだけで、Security Headersの設定状況を分析し、グレード(A+からFまで)で評価してくれます。
不足しているヘッダや改善点も教えてくれるため、初心者にとって非常に有用です。

HTTP Observatory

Mozillaが提供する無料のセキュリティスキャンツールです。
Security Headersだけでなく、サイト全体のセキュリティ状態を包括的にチェックしてくれます。

コマンドラインでの確認(curl)

開発者の方は、curlコマンドを使った確認も便利です。

curl -I https://____.com

このコマンドを実行すると、レスポンスヘッダがターミナルに表示されます。
-Iオプションはヘッダ情報のみを取得するオプションです。

より詳細に特定のヘッダだけを確認したい場合は、以下のようにgrepを組み合わせます。

curl -I https://____.com | grep -i "x-frame-options"

これにより、X-Frame-Optionsヘッダだけが抽出されて表示されます。

よくある質問と注意点

リンドくん

リンドくん

Security Headersを設定すると、サイトの動作に影響が出たりしませんか?

たなべ

たなべ

確かにContent-Security-Policyなどは厳しすぎる設定にすると、意図した機能が動かなくなることがあるんだ。だから段階的に導入していくことが大切なんだよ。

Content-Security-Policyで既存機能が動かなくなった場合

CSPを導入すると、インラインのJavaScriptやCSSがブロックされることがあります。
例えば、以下のようなコードは厳格なCSP設定では動作しません。

<!-- このようなインラインスクリプトはブロックされる -->
<button onclick="alert('Hello')">クリック</button>

<script>
  console.log('This is inline script');
</script>

解決策

  1. 外部ファイル化する - スクリプトを別ファイルに分離
  2. nonce(ノンス)を使用する - 特定のインラインスクリプトのみ許可
  3. 段階的に厳格化する - 最初はunsafe-inlineを許可し、徐々に制限
<!-- nonce(ワンタイムトークン)を使った許可 -->
<script nonce="ランダムな値">
  console.log('This is allowed');
</script>

HSTSの設定前に必ず確認すべきこと

HSTSを有効にする前に、以下を必ず確認してください。

  • サイト全体がHTTPSで正しく動作する - リンク切れやMixed Contentエラーがないか
  • サブドメインもHTTPS対応している - includeSubDomainsを使う場合
  • テスト期間を設ける - 最初は短いmax-age(例:300秒)で試す

一度HSTSを有効にすると、指定期間中はHTTPでのアクセスが完全にブロックされます。
慎重に段階的に導入することが重要です。

複数のSecurity Headersを同時に設定する際の優先順位

複数の場所(サーバ設定とアプリケーションコード両方)でSecurity Headersを設定すると、重複や競合が発生する可能性があります。

ベストプラクティス

  • Webサーバレベルでの設定を推奨 - すべてのレスポンスに確実に適用される
  • アプリケーションレベルでは個別対応が必要な場合のみ - 特定のページだけ設定を変えたい場合
  • 設定の一元管理 - どこで設定しているか明確にドキュメント化する

レガシーブラウザへの対応

古いブラウザは一部のSecurity Headersに対応していません。
しかし、これは問題ではありません。

  • 対応ブラウザでは保護される - モダンブラウザユーザーの安全性が向上
  • 非対応ブラウザでも害はない - 単に無視されるだけで、エラーにはならない
  • 段階的な保護 - 時間とともにユーザーがモダンブラウザに移行

つまり、古いブラウザのユーザーがいても、Security Headersの設定を躊躇する必要はありません。

まとめ

リンドくん

リンドくん

Security Headersって、思ったより簡単に設定できるんですね!すぐに試してみたくなりました。

たなべ

たなべ

その意気だよ!Security Headersはサーバ設定やコードに数行追加するだけで、多くの攻撃から守れる強力な防御策なんだ。ぜひ実践してみてね!

本記事では、Webセキュリティの基本となるSecurity Headersについて、基礎から実践まで詳しく解説してきました。
重要なポイントを改めて整理しましょう。

  • X-Frame-Options - クリックジャッキング攻撃を防ぐ
  • X-Content-Type-Options - MIMEタイプスニッフィング攻撃を防ぐ
  • Content-Security-Policy - XSSなどの様々な攻撃を防ぐ強力なヘッダ
  • Strict-Transport-Security - HTTPS通信を強制して中間者攻撃を防ぐ

Webセキュリティは難しそうに感じるかもしれませんが、Security Headersのように一つ一つ確実に実践できる対策から始めれば大丈夫です。

あなたが開発したWebサイトやアプリケーションに、今日学んだSecurity Headersを設定してみてください。
それだけで、多くの攻撃からユーザーを守ることができます。

セキュリティは「完璧」を目指すのではなく、「継続的に改善する」ことが大切です
まずは今日学んだSecurity Headersの設定から始めて、一歩ずつステップアップしていきましょう。

この記事をシェア

関連するコンテンツ