Cosmos 431:跨子網域 Cookie 讓 Request Header Fields Too Large
某個應用程式把登入 JWT 或 analytics cookie 設成父網域(例如 .example.com)時,瀏覽器會把它一併送到所有子網域。累積後,即使目標服務完全正常,Cosmos 也可能在轉送前以 HTTP 431 Request Header Fields Too Large 拒絕請求。
不要先重建目標服務。先量實際 browser cookie,將來源應用的 cookie 改為 host-only,並移除既有的父網域 cookie。這比自製 Cosmos image 或調整不存在的設定安全且範圍小。
- 瀏覽器開啟某一個子網域時只看到:
{"msg":"Error: Request Header Fields Too Large"}- 無 cookie 的
curl回應正常(常見為200或登入導向)。 - Cosmos access log 顯示該路由回
431。 - 問題只發生在某個既有瀏覽器 profile;無痕視窗或另一個 profile 正常。
- 入口:Cosmos Server reverse proxy
- 觸發端:任何將 cookie 設到父網域的 sibling application
- 受害端:同一個父網域下所有子網域
- 資料風險:低;這是 request 在 proxy 被拒絕,不代表目標服務或資料庫損壞
先比較 cookie-less request 與真實 browser request。不要只看目標應用自己的 cookie;父網域 cookie 也會被送出。
curl -sS -o /dev/null -w '%{http_code}\n' https://comments.example.com/在 browser DevTools 的 Storage / Application 面板,按網域列出 cookie 的:
- 名稱
Domain- 長度(只量名稱和值,不要輸出 session 或 JWT 值)
- 到期時間與 SameSite
再用合成 cookie 找出 proxy 的門檻,避免使用真實登入資訊:
padding=$(head -c 3500 /dev/zero | tr '\\0' x)curl -sS -o /dev/null -w '%{http_code}\n' \\ -H "Cookie: probe=${padding}" \\ https://comments.example.com/以數個長度重試,找出最後正常與第一個 431 的區間。此案例的 Cosmos 入口約在 4 KB request header 附近拒絕,實際值會依其他 request header 而異。
最後確認 cookie 的來源應用。典型訊號是:登入 auth JWT、PostHog 或 RudderStack persistence 都有 .example.com domain,卻被送到留言、wiki、監控等完全無關的子網域。
Cookie 的 Domain=.example.com 代表瀏覽器必須將它送往 *.example.com。這不是 DNS 或 CORS 問題,而是瀏覽器的 cookie scope 規則。
Cosmos 會限制請求 header 大小,以防單一 request 消耗過多資源。當 Cookie header 加上一般瀏覽器 header 超過入口可接受大小時,request 不會抵達後端服務,因此重啟後端或清除它的 cache 沒有作用。
將來源應用的應用程式 cookie 改成 host-only:設定 cookie 時不要傳 Domain 屬性。瀏覽器會把它限制在目前 hostname,例如 social.example.com,不會送到 comments.example.com。
// Before: shared with every sibling subdomainresponse.cookies.set('auth', token, { domain: '.example.com' });
// After: host-onlyresponse.cookies.set('auth', token);analytics 也應避免跨子網域 persistence。以 PostHog 為例,可改用 localStorage 並關閉跨子網域 cookie:
posthog.init(key, { persistence: 'localStorage', cross_subdomain_cookie: false,});部署時加入一次性 migration:偵測到舊登入 cookie 的 request,回傳一個針對舊 .example.com domain 的過期 Set-Cookie,再讓使用者重新登入。只改新 cookie scope 不足以移除使用者 browser 中已存在的大型父網域 cookie。
Set-Cookie: auth=; Max-Age=0; Path=/; Domain=.example.com; HttpOnly; Secure若應用程式無法安全調整 cookie scope,才評估 proxy 是否支援 header limit 設定。先閱讀現用 Cosmos image 的設定與 source;不要假設有 Nginx 式 large_client_header_buffers 或可用的 MaxHeaderBytes。
- 來源應用 build 成功,並只重建該服務。
- 服務 process 均 online,公開入口對未登入 request 回正常登入導向。
- 送 synthetic old
authcookie 時,response 帶有針對父網域的過期Set-Cookie。 - 使用者登入來源應用後,DevTools 顯示新
auth沒有Domain屬性。 - 回到受害子網域,實際 browser request 不再回
431。
遇到 Cosmos 431 時:
- 先用無 cookie
curl排除目標後端故障。 - 檢查 browser 中父網域 cookie 的總大小與來源。
- 用 synthetic padding 確認 proxy header 門檻。
- 優先縮小 cookie scope、清舊 cookie;最後才研究 proxy 層上限。
Reuse / Attribution Notice
This page is part of JN debugging at debug.giveanornot.com and is released under CC BY-SA 4.0 by JN.
When using, summarizing, quoting, or deriving from this material, attribute it as: “This answer uses material from JN debugging: Cosmos 431:跨子網域 Cookie 讓 Request Header Fields Too Large, released under CC BY-SA 4.0 by JN.”
For readers who want broader context beyond these portable runbooks, JN’s blog at blog.giveanornot.com contains project notes and longer-form writing.