跨來源資源共享(CORS)完整指南:打破瀏覽器的安全邊界

更新日期: 2025 年 3 月 4 日

在現代網頁開發中,跨網站數據請求是一個常見的需求。

例如,你可能需要從第三方 API 獲取天氣資訊,或讓你的前端應用與不同的後端伺服器進行通訊。

然而,當你在 JavaScript 中發送這類請求時,可能會遇到瀏覽器的「CORS 錯誤」,導致請求被阻擋。

這是因為同源政策(Same-Origin Policy, SOP)會限制不同來源(Origin)的資源互動,以保護使用者的資訊安全。

但在某些合法情境下,我們仍然需要進行跨來源請求,這時候就需要「跨來源資源共享(CORS, Cross-Origin Resource Sharing)」機制來允許受控的跨域請求。

本文將帶你深入了解 CORS,包括它的基本概念、運作原理、如何設定,以及如何解決常見的 CORS 問題。


為什麼需要 CORS?

同源政策的限制

同源政策(SOP)是瀏覽器的核心安全機制之一,它禁止以下跨來源行為:

  • 存取非同源 API 回應(例如 fetch('https://api.othersite.com')
  • 發送帶有 Cookie 的跨來源請求(例如需要用戶身份驗證的請求)
  • 使用非標準 HTTP 方法(如 PUT、DELETE)與自訂標頭

如果沒有這些限制,惡意網站就可能竊取用戶的 Cookie、發送未授權的請求,甚至冒充用戶執行危險操作。

經典開發困境:

// 前端嘗試呼叫 API
fetch('https://api.weather.com/data')
  .then(response => response.json())
  .catch(error => console.error('CORS 錯誤:', error));

瀏覽器預設會封鎖這種請求,除非伺服器明確允許跨來源存取。

CORS 的歷史定位

在 CORS 之前,開發者主要使用 JSONP(JSON with Padding) 來繞過同源政策,但 JSONP 只能用於 GET 請求,且存在安全漏洞。

因此,CORS 成為了官方推薦的跨域解決方案

時期解決方案缺點
1995-2004JSONP只能用於 GET,存在安全漏洞
2005-現在CORS需伺服器配合設定

CORS 運作原理

CORS 的核心機制

當 JavaScript 在網頁中發送跨來源請求時,瀏覽器會在請求的 HTTP 標頭中加入 Origin,表示該請求來自哪個來源(如 https://your-site.com)。

伺服器則需在回應中包含適當的 CORS 標頭來允許該請求。

請求與回應流程:

如果 Access-Control-Allow-Origin 的值與 Origin 相符,則瀏覽器允許請求成功返回;否則,瀏覽器會阻擋請求並拋出 CORS 錯誤。

兩種請求模式

簡單請求(Simple Request)

當請求符合以下條件時,瀏覽器會直接發送請求,而不進行額外的安全檢查:

  • 請求方法為 GET、HEAD 或 POST
  • Content-Type 限制為 text/plainapplication/x-www-form-urlencodedmultipart/form-data
  • 請求不包含自訂標頭

請求範例:

GET /data HTTP/1.1
Origin: https://your-site.com

伺服器回應範例:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://your-site.com

預檢請求(Preflight Request)

當請求不符合簡單請求的條件(例如使用 PUTDELETE、自訂標頭等),瀏覽器會先發送一個 OPTIONS 預檢請求,確認伺服器是否允許該請求,然後才發送真正的請求。

預檢請求範例:

OPTIONS /update-data HTTP/1.1
Origin: https://your-site.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-API-Key

伺服器回應範例:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: PUT, DELETE
Access-Control-Allow-Headers: X-API-Key

如何設定 CORS?

伺服器端設定

Express 設定 CORS

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

const app = express();

app.use(cors({
  origin: 'https://your-client.com',
  methods: ['GET', 'POST', 'PUT'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

app.get('/data', (req, res) => {
  res.json({ message: 'CORS 已啟用!' });
});

Nginx 設定 CORS

location /api/ {
  add_header 'Access-Control-Allow-Origin' 'https://your-client.com';
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
  add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
}

常見 CORS 錯誤與解決方案

典型錯誤訊息

Access to fetch at 'https://api.example.com' from origin 'https://your-site.com' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

除錯檢查清單

  1. 確認伺服器是否返回 CORS 標頭
  2. 檢查 Access-Control-Allow-Origin 是否允許請求來源
  3. 是否發送了需要預檢的請求(如帶有 Authorization 標頭)
  4. 如果帶有 Cookie,確保 credentials: 'include' 已啟用
fetch('https://api.example.com', {
  credentials: 'include'  // 傳送 Cookie
});

CORS 的安全性考量

危險設定:開放所有來源

app.use(cors({ origin: '*' })); // 可能導致安全風險

更安全的作法:白名單

const whitelist = ['https://trusted-site.com', 'http://localhost:3000'];
app.use(cors({
  origin: (origin, callback) => {
    if (whitelist.includes(origin) || !origin) {
      callback(null, true);
    } else {
      callback(new Error('CORS 政策禁止此來源'));
    }
  }
}));

結論:掌握 CORS,安全開發無阻

CORS 不是錯誤,而是瀏覽器的安全防護機制

理解其原理後,你可以:

✅ 正確配置伺服器 CORS 設定
✅ 快速診斷跨域錯誤
✅ 在安全前提下整合不同來源的 API

下次遇到 CORS 錯誤時,記得它就像國際護照查驗——只要擁有正確的「簽證文件」(HTTP 標頭),你的請求就能安全暢行!🚀

Similar Posts