
【AI文芸】玲奈の一夜 - CORS
🔹1. 午前2時、緊急コール
真夜中、オフィスが静まり返る中、玲奈のスマホが震えた。
ディスプレイには赤い文字──“Critical Alert: Unauthorized access detected”。
「またかよ…」
眠気で霞む目を無理やり開き、Slackを開く。
社内チャンネルがざわついている。
SREチームが脅えるように状況をやりとりしている。
「異常アクセスが止まらない」「海外IPだ」「アクセスログが数万行を突破」
玲奈はため息をつきながら身支度を整える。
「真夜中に呼び出されんの、もう何度目だっけ?」
そう思いながらも、彼女は急いでタクシーに飛び乗った。
🔹 2. オフィス到着、漂う不穏な空気
午前2時半。
普段から薄暗いオフィスだが、今日はさらに重い空気が漂っている。
SOC(セキュリティオペレーションセンター)のモニターには真っ赤なログが流れ続けていた。
玲奈:「状況は?」
SOCスタッフの長谷川が必死にキーボードを叩きながら答える。
長谷川:「アクセス元はロシア、中国、東欧…IPを変えながら大量リクエストしてます。AWSのWAFが阻止しきれず、APIに直撃してるみたいで…」
玲奈:「APIのどこ?」
長谷川:「/user-info と /account/balance 辺りですね。どうやら本番環境からユーザー情報を引っ張ろうとしているようで…」
玲奈は顔をしかめる。
「……最悪だな」
🔹 3. 田辺、現る
その時、汗だく で駆け込んできたのは開発チームの田辺。
Tシャツが汗でびっしょりだ。息が荒い。
田辺:「ちょ、ちょっとヤバいっすね…?」
玲奈は田辺を冷淡な目で見る。
「お前、本番APIのCORS、どう設定してた?」
田辺は口ごもった。
「え、えっと…確か CorsLayer::permissive() か、allow_origin(Any)…」
玲奈:「"allow_origin(Any)" ?」
そう呟いた瞬間、周囲のスタッフが息を飲んだ。
CORSの専門知識がなくても、「これヤバいやつだ」ってのが分かる。
🔹 4. 問題のコード、露呈
玲奈は急いでリポジトリを検索し、該当箇所のコードを開く。
use tower_http::cors::{CorsLayer, Any};
let cors = CorsLayer::new()
.allow_origin(Any) // ❌
.allow_methods(Any)
.allow_headers(Any);
玲奈:「…はぁ??」
その苛立ちをこめた吐息に、田辺がビクッとする。
「マジで、"どこからでもアクセスOK" にしてんの?これ本番用のサーバーだよな?」
「だ、だってフロントエンドの開発中にCORSエラーが面倒で…」
「お前さあ…」
玲奈は机を殴るでもなく、静かに椅子に座り込んだ。むしろ、その沈黙が怖い。
🔹 5. インシデントのヤバさ
田辺は怖々と口を開く。
「で、でもこれ、すぐ直せば大丈夫ですよね?」
玲奈:「…甘いよ。もう既に海外IPから大量アクセスされてんだろ?どう考えてもデータが狙われてるんだよ。
ユーザー情報が抜かれてるかもしれない。」
田辺は青ざめる。
「…え、えっと、どうしよう…」
「お前は黙ってろ。さっさとコード直して再デプロイしろ」
玲奈は早口でSOCチームに指示を飛ばす。
AWS WAFで特定のIPを遮断
NGINXのリバースプロキシでレートリミット設定
SIEMでログを徹底分析
PR出たらすぐに本番反映
田辺:「え、ちょっと、PRって今から…?」
玲奈は無言でスクリーンを指差す。
「30秒で作れ。
次に "Any" の文字列見つけたら、お前、デプロイ権限剥奪な」
🔹 6. 緊迫の修正作業
田辺は震える手でコードを修正する。
let cors = CorsLayer::new()
.allow_origin("https://frontend.example.com".parse().unwrap()) // ✅ 特定のオリジンのみ
.allow_methods([Method::GET, Method::POST]) // ✅ 必要なメソッドだけ
.allow_headers(["Authorization", "Content-Type"]) // ✅ 必要なヘッダーだけ
.allow_credentials(true) // ✅ 認証情報を送れる
.use_max_age(std::time::Duration::from_secs(86400)); // プリフライトリクエストキャッシュ
田辺の背後で玲奈が腕を組み、じっと見つめている。
「フロントエンドが "OPTIONS" でちょいちょい文句言うなら max_age() で押さえ込めるだろ。
"Any" は二度と使うな。」
🔹 7. デプロイ、怒涛のコミット
午前3時。
修正がコミットされ、CIパイプラインが回り始める。
テストが通り、わずか10分後に本番サーバーへデプロイが完了。
SOCのスタッフはアクセスログを監視する。
多少はまだ攻撃リクエストが来ているが、CORSポリシーの適切化+WAF設定 で応答はブロックされる。
長谷川:「ログイン必須APIにはもうアクセスできていません。データ漏洩の兆候は…今のところなし!」
玲奈はようやく肩の力を抜く。
田辺は椅子にもたれかかり、安堵の息をついた。
🔹 8. 玲奈の一喝
「田辺。今回のことで分かったよな?」
田辺は小さく頷く。
「…CORSを適当に設定しちゃいけない、ですよね」
「そうだ。お前の "めんどくさい" で、会社が潰れる可能性があったんだよ。」
玲奈は田辺のディスプレイをじっと睨む。
「次に同じミスをしたら、nano で IDE 設定ファイルごと書き換えさせるからな。」
「ひいいいいっ!!」
🔹 9. 余波
午前4時過ぎ。
インシデントは一応の収束を見せたが、SOCは引き続き監視を続ける。
田辺は警戒心に怯えた顔のまま、ログを眺めている。
玲奈はスマホを眺め、再びため息をつく。
「…この時間に呼び出されるの、ほんと勘弁してほしいんだけど」
「CORSを舐めた開発者がいる限り、私の睡眠時間は増えないんだな」
そう呟き、玲奈はペットボトルのお茶を一気に飲み干した。
夜はまだ終わらない。
🎯 まとめ
深夜2時のインシデントは最悪: 攻撃者は夜間を狙う。
CORS設定ミスは重大: 「許可してはいけないオリジン」を開放すれば、情報漏洩の危機。
"Any" は地獄の入り口: 本番では特定オリジン指定+allow_credentials(true) の正しい設定が必須。
セキュリティインシデントは即対応: 放置すれば会社の信用が消し飛ぶ。
玲奈の一喝: 二度と同じミスをするな。夜中の呼び出しはもうごめんだ。