CORS跨域檢查器
跨域診斷面板
由伺服端模擬預檢與實際請求,快速判斷是 Allow-Origin、Allow-Headers 還是 credentials 出了問題。
在伺服器真實模擬CORS預檢與實際請求,6大回應標頭逐項檢查,精準定位跨域設定錯誤,提供Nginx/Node.js/Spring等多框架修復程式碼。
由伺服端模擬預檢與實際請求,快速判斷是 Allow-Origin、Allow-Headers 還是 credentials 出了問題。
在伺服器真實模擬CORS預檢與實際請求,6大回應標頭逐項檢查,精準定位跨域設定錯誤,提供Nginx/Node.js/Spring等多框架修復程式碼。
這是最經典的CORS問題!因為Postman和curl根本不受瀏覽器同源政策限制——它們是HTTP用戶端,不是瀏覽器,不會攔截回應,也不會自動發OPTIONS預檢請求。跨域錯誤是瀏覽器獨有的安全機制,只有瀏覽器的JavaScript執行環境才會執行CORS檢查。Postman能調通只能證明介面本身能回傳資料,不能證明CORS設定正確。你需要用瀏覽器、或者本工具(伺服器模擬瀏覽器CORS流程)來偵測,才會發現問題。
99%的CORS錯誤是後端設定問題(或者Nginx/閘道層設定問題),前端能做的非常有限。CORS的核心是伺服器透過回應標頭「授權」瀏覽器允許跨域存取,前端只能設定withCredentials、設定請求標頭這些,無法繞過瀏覽器的安全限制。網上說的前端用代理(devServer proxy、Nginx反向代理把前端和介面代理到同個源)本質是「欺騙」瀏覽器讓它以為是同源請求,不是真的解決了CORS問題,生產環境如果前後端不同源還是需要後端正確設定CORS。
因為GET通常滿足簡單請求條件,瀏覽器直接發請求;而POST如果你發的是Content-Type: application/json(90%的POST介面都是這個),就不屬於簡單請求了,會觸發OPTIONS預檢。預檢請求需要伺服器回傳正確的CORS標頭,很多人只給GET/POST配了CORS標頭但沒處理OPTIONS方法,或者OPTIONS回應沒帶頭,就報錯了。PUT/DELETE/PATCH這些方法本身就不是簡單方法,必然觸發預檢。
開發環境有幾種方案:①框架內建的代理(Vue CLI的devServer.proxy、Vite的server.proxy、Create React App的proxy):把介面請求代理到前端開發伺服器同源,瀏覽器以為是同源請求不跨域;②關閉瀏覽器安全參數(比如Chrome加--disable-web-security啟動參數),僅限本機臨時測試,絕對不能用於正常瀏覽;③後端設定CORS允許localhost源(推薦,和生產環境行為一致)。生產環境必須後端正確設定CORS:設定允許的源白名單、正確設定Allow-Methods/Allow-Headers/Allow-Credentials、加Vary: Origin,或者用閘道/Nginx統一處理CORS。
不行,Access-Control-Allow-Origin回應標頭只能有一個值,要麼是具體的一個源(如https://a.com),要麼是*。瀏覽器不接受多個源(比如寫https://a.com,https://b.com是無效的,瀏覽器會認為不匹配)。正確的多源設定方式是:伺服器維護一個允許的源白名單清單,每次收到請求時讀取請求標頭中的Origin值,檢查這個Origin是否在白名單中,如果在就把Access-Control-Allow-Origin設定為這個具體的Origin值,同時回傳Vary: Origin頭;如果不在就不回傳CORS頭或者回傳錯誤。不要試圖回傳多個Allow-Origin頭或者用逗號分隔多個值,瀏覽器都不認。
OPTIONS預檢請求不需要回傳任何業務邏輯和回應本文,只需要回傳正確的CORS回應標頭和200/204狀態碼就可以了。瀏覽器收到正確的CORS頭就認為預檢通過,不會讀取OPTIONS回應的body內容。所以最佳實務是:在Nginx/閘道層直接攔截OPTIONS請求,回傳204 No Content和正確的CORS頭,不轉發到後端應用程式伺服器,這樣既減輕後端壓力,也避免後端路由不支援OPTIONS導致的405錯誤。但要注意確保OPTIONS回應的CORS頭和實際請求的CORS頭保持一致。
帶Cookie的跨域請求需要同時滿足三個條件:①前端XMLHttpRequest.withCredentials = true或者fetch的credentials: 'include';②後端回應標頭Access-Control-Allow-Credentials: true;③Access-Control-Allow-Origin不能是*,必須是具體源。三個條件缺一不可。另外還要注意Cookie的屬性:Cookie必須設定了SameSite=None; Secure(HTTPS環境)才能在跨域請求中攜帶;如果Cookie是SameSite=Lax或Strict,跨域請求不會帶;Cookie的Domain屬性要正確設定;還要注意第三方Cookie政策的影響(Chrome等瀏覽器對第三方Cookie有限制)。
CORS是放寬跨域存取限制,CSRF是跨站請求偽造攻擊,兩者是不同概念。正確設定CORS不會直接導致CSRF漏洞——因為CORS只是允許JS讀取回應,而CSRF是攻擊者誘導使用者在不知情的情況下發送請求(比如img標籤、自動提交表單),這些請求即使沒有CORS也會發出去帶上Cookie。防禦CSRF需要用CSRF Token、SameSite Cookie、驗證Origin/Referer等方案,不能靠停用CORS來防CSRF。但如果你設定CORS時把Allow-Origin設為*且允許帶憑證,確實會放大CSRF風險,所以帶憑證場景絕對不能用*,必須嚴格限制白名單源。
普通的<img>、<script>、<link>標籤載入跨域資源(CDN圖片、JS指令碼、CSS)預設不會有CORS問題,這些是「嵌入資源」不是「AJAX請求」,瀏覽器允許載入但JS不能讀取內容。但如果你想在Canvas中操作跨域圖片、或者用fetch/XHR載入這些資源並讀取內容,就需要CORS,同時標籤上要加crossorigin屬性。跨域檔案下載(a標籤點擊下載)預設也不需要CORS。重新導向會影響CORS:預檢OPTIONS請求如果回傳3xx重新導向,瀏覽器會直接拒絕(Preflight redirect is not allowed);實際請求的重新導向如果是跨源的,需要每一跳都正確回傳CORS頭。
Nginx推薦設定要點:①用map指令匹配Origin白名單,動態設定$cors_origin變數;②OPTIONS請求直接回傳204不轉發後端;③add_header記得加always參數確保錯誤回應也帶頭;④加上Vary: Origin;⑤正確設定Allow-Methods/Allow-Headers/Credentials。範例設定可以在本工具偵測結果的修復建議中找到,針對Nginx、Apache、Node.js Express、Spring Boot、Python Flask/Django、Koa、Go Gin等主流框架我們都提供了經過驗證的設定片段。
驗證CORS的幾個步驟:①先用本工具線上偵測,輸入URL、Origin、方法、頭、憑證選項,看預檢和實際請求的各項檢查是否通過;②打開瀏覽器DevTools的Network面板,勾選Disable cache停用快取(避免舊快取干擾),觸發跨域請求,檢查OPTIONS預檢和實際請求的回應標頭是否正確;③在Console看有沒有CORS相關錯誤;④測試不同場景:不帶自訂頭的GET請求、帶application/json的POST請求、PUT/DELETE方法、帶Cookie/不帶Cookie、帶自訂頭;⑤用curl模擬OPTIONS請求:curl -i -X OPTIONS -H "Origin: https://yoursource.com" https://api.example.com/endpoint,檢查回應標頭是否正確。
不同瀏覽器對CORS規範的實作細節有差異:①Safari對預檢快取Max-Age限制更嚴格(早期版本只有600秒),Cookie策略(ITP智慧反追蹤)也更嚴格,可能導致跨域Cookie問題;②Chrome對帶憑證時的萬用字元檢查更嚴格,Allow-Headers/Allow-Methods也不允許*,Firefox某些版本可能寬鬆些;③舊版IE(IE11)用的是XDomainRequest而不是標準XMLHttpRequest,CORS實作有很多坑(比如不支援自訂頭、只支援GET/POST);④不同瀏覽器對Vary頭的處理、重新導向處理、安全頭的處理有細微差異。解決方法是嚴格按照CORS規範設定,不要依賴某一個瀏覽器的相容行為。
建議設定為3600(1小時)到86400(24小時)之間。設定太短(比如60秒):預檢快取很快過期,頻繁發送OPTIONS請求,增加請求耗時和伺服器壓力,在行動弱網環境下影響明顯。設定太長(比如31536000即一年):如果你更新了CORS設定(比如新增了允許的方法、頭),使用者瀏覽器快取的舊預檢結果可能要很久才過期,期間會出現設定不生效的問題。另外Chrome和Firefox會自動把超過86400秒的值截到86400秒,你設再長也沒用。開發環境可以設定為-1停用預檢快取,方便除錯。
WebSocket(ws://和wss://)不受HTTP CORS機制限制,因為WebSocket是獨立的通訊協定,不是HTTP AJAX請求。但WebSocket交握階段是HTTP請求,伺服器可以檢查Origin頭來決定是否允許連線——這是WebSocket層面的權限控制,不是標準CORS,但原理類似。如果WebSocket連線被拒絕,你需要檢查WebSocket服務端的Origin校驗設定,而不是HTTP CORS頭。Socket.IO等函式庫可能有自己的跨域設定方式,和標準CORS設定類似但不完全一樣。另外,HTTP/2 Server Push、WebRTC等其他瀏覽器API也有各自的權限控制,不完全遵循HTTP CORS。
本工具在伺服器嚴格按照W3C CORS規範模擬瀏覽器的預檢和實際請求流程,對CORS頭的檢查邏輯和現代瀏覽器基本一致。如果工具偵測通過但瀏覽器還是報錯,可能的原因:①瀏覽器快取了舊的預檢結果或回應,按Ctrl+F5強制重新整理或者清除快取再試;②瀏覽器擴充功能(廣告封鎖、隱私保護、安全外掛)修改或攔截了請求;③你在工具中填寫的Origin、請求標頭、方法、憑證選項和實際前端發送的不一致(比如前端實際還帶了某個自訂頭但你沒在工具裡加);④CDN/代理節點快取不一致,工具請求的節點和瀏覽器請求的節點回傳不同結果;⑤瀏覽器有特殊安全策略(比如HTTPS頁面請求HTTP混合內容被攔截、本機檔案file://協定的特殊限制)。