從零手寫實現 nginx-19-HTTP CORS(Cross-Origin Resource Sharing,跨源資源共享)介紹+解決方案

老马啸西风發表於2024-06-12

前言

大家好,我是老馬。很高興遇到你。

我們為 java 開發者實現了 java 版本的 nginx

https://github.com/houbb/nginx4j

如果你想知道 servlet 如何處理的,可以參考我的另一個專案:

手寫從零實現簡易版 tomcat minicat

手寫 nginx 系列

如果你對 nginx 原理感興趣,可以閱讀:

從零手寫實現 nginx-01-為什麼不能有 java 版本的 nginx?

從零手寫實現 nginx-02-nginx 的核心能力

從零手寫實現 nginx-03-nginx 基於 Netty 實現

從零手寫實現 nginx-04-基於 netty http 出入參最佳化處理

從零手寫實現 nginx-05-MIME型別(Multipurpose Internet Mail Extensions,多用途網際網路郵件擴充套件型別)

從零手寫實現 nginx-06-資料夾自動索引

從零手寫實現 nginx-07-大檔案下載

從零手寫實現 nginx-08-範圍查詢

從零手寫實現 nginx-09-檔案壓縮

從零手寫實現 nginx-10-sendfile 零複製

從零手寫實現 nginx-11-file+range 合併

從零手寫實現 nginx-12-keep-alive 連線複用

從零手寫實現 nginx-13-nginx.conf 配置檔案介紹

從零手寫實現 nginx-14-nginx.conf 和 hocon 格式有關係嗎?

從零手寫實現 nginx-15-nginx.conf 如何透過 java 解析處理?

從零手寫實現 nginx-16-nginx 支援配置多個 server

從零手寫實現 nginx-17-nginx 預設配置最佳化

從零手寫實現 nginx-18-nginx 請求頭+響應頭操作

從零手寫實現 nginx-19-nginx cors

從零手寫實現 nginx-20-nginx 佔位符 placeholder

從零手寫實現 nginx-21-nginx modules 模組資訊概覽

從零手寫實現 nginx-22-nginx modules 分模組載入最佳化

從零手寫實現 nginx-23-nginx cookie 的操作處理

從零手寫實現 nginx-24-nginx IF 指令

HTTP CORS 是什麼?

HTTP CORS(Cross-Origin Resource Sharing,跨源資源共享)是一種安全機制,它允許一個網頁(執行在瀏覽器中的網頁)去請求另一個不同源(域名、協議或埠不同)的資源。

想象一下,網際網路上的每個網站都有自己的“家”,並且通常只能訪問自己家裡的東西。

但是,有時候一個網站需要訪問另一個網站的資料或資源,比如圖片、影片或API。如果沒有CORS,這種訪問是不被允許的,因為瀏覽器出於安全考慮會阻止這種跨源請求。

CORS機制允許網站“告訴”瀏覽器,它信任哪些外部網站,並允許它們訪問自己的資源。

這樣,當一個網站請求另一個網站資源時,瀏覽器會檢查這個請求是否被允許。如果允許,瀏覽器就會允許這次請求,否則會阻止。

簡單來說,CORS就像是一個“通行證”,它讓不同的網站之間可以安全地共享資源。

為什麼需要 HTTP CORS?

HTTP CORS(跨源資源共享)之所以需要,主要是為了保護使用者和網站資料的安全,同時也提供了一種機制來允許安全地跨網站訪問資源。

為什麼需要CORS:

想象一下,你有一個自己的圖書館(網站A),而你的朋友有一個不同的圖書館(網站B)。通常,你只能借閱你自己圖書館裡的書籍,不能直接去朋友圖書館借書。這是因為每個圖書館都有自己的規則和隱私政策,它們不希望其他人隨意訪問自己的書籍。

但是,有時候你需要借閱朋友圖書館裡的一本書,這時候就需要一種機制來確保這個過程是安全的。CORS就相當於是一張“借書證”,它允許你的朋友圖書館知道你想要借書,並且決定是否允許你借閱。

如果沒有CORS這樣的機制,任何圖書館的人都可以隨意去其他圖書館借書,這可能會導致一些問題:

  1. 隱私問題:圖書館的書籍可能包含敏感資訊,不應該被未經授權的人訪問。

  2. 安全問題:如果有人惡意訪問圖書館,可能會造成書籍損壞或資訊洩露。

  3. 管理問題:圖書館需要能夠控制誰可以借閱書籍,以及借閱的條件。

透過CORS,網站可以明確哪些外部網站是可信的,並且可以設定規則來控制它們如何訪問資源。

這樣,既保護了網站的資源不被濫用,又允許了安全的跨網站互動,比如社交媒體登入、API呼叫等。

簡而言之,CORS是網路安全和資源共享之間的一個平衡點。

開發過程中遇到了 CORS 限制,如何解決?

遇到CORS(跨源資源共享)限制時,通常有以下幾種解決方法,分別針對後端、前端和瀏覽器:

後端解決方法

  1. 設定Access-Control-Allow-Origin響應頭
    在伺服器響應中新增Access-Control-Allow-Origin頭,指定允許訪問的源。例如,如果你想允許所有源訪問你的資源,可以設定為*(不推薦,因為不安全):

    Access-Control-Allow-Origin: *
    

    或者指定具體的源:

    Access-Control-Allow-Origin: https://www.example.com
    
  2. 處理預檢請求(Preflight Request)
    對於某些型別的請求,瀏覽器會先傳送一個預檢請求(OPTIONS請求),詢問伺服器是否允許實際的請求。伺服器需要正確響應這個OPTIONS請求,並在響應中包含必要的CORS頭資訊。

  3. 設定其他CORS相關的響應頭

    • Access-Control-Allow-Methods:指定允許的HTTP方法,如GET, POST等。
    • Access-Control-Allow-Headers:指定允許的自定義請求頭。
    • Access-Control-Allow-Credentials:如果需要攜帶憑證(如cookies),則需要設定為true
    • Access-Control-Max-Age:指定預檢請求的快取時間。

前端解決方法

  1. 使用代理伺服器

    在開發過程中,可以透過設定一個代理伺服器來繞過CORS限制。

    例如,使用Webpack的devServer.proxy配置或Node.js的http-proxy-middleware。

  2. 使用CORS代理服務
    對於一些簡單的請求,可以使用公共的CORS代理服務,如https://cors-anywhere.herokuapp.com/

  3. 同源策略
    確保前端應用和後端服務部署在同一源(相同的協議、域名和埠)。

Chrome 瀏覽器解決方法

老馬推薦直接修改啟動引數:

修改啟動引數

你可以使用 --disable-web-security 引數來啟動 Chrome,這樣可以禁用瀏覽器的同源策略和 CORS 安全特性,從而允許跨域請求。

例如,可以在命令列中使用以下引數來啟動 Chrome:

chrome.exe --user-data-dir="D://Chrome dev session" --disable-web-security

此外,還可以透過設定 --args 引數來實現類似的效果,如搜尋結果[3]所示:

--args --disable-web-security --user-data-dir=D:\HaoroomsChromeUserData

或者在 macOS 上使用以下命令:

open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/Eric/MyChromeDevUserData/

請注意,這些方法僅適用於開發環境,不推薦在生產環境中使用,因為這會降低瀏覽器的安全性。

此外,如果遇到跨域 cookies 問題,還可以透過訪問 chrome://flags 並禁用 SameSite by default cookiesCookies without SameSite must be secure 選項來解決[3]。

其他方式:

  1. 使用Chrome擴充套件
    安裝一些允許CORS的Chrome擴充套件,如Allow CORS: Access-Control-Allow-Origin

  2. 開發者工具中的CORS禁用

    在Chrome的開發者工具中,可以臨時禁用CORS限制。

    但是,這種方法只適用於開發和測試,不應用於生產環境。

    • 開啟Chrome的開發者工具。
    • 點選“Network”(網路)標籤。
    • 在右側的“Request Blocking”(請求攔截)部分,勾選“Disable cache”(禁用快取)和“Disable CORS”(禁用CORS)。

注意

  • 安全考慮:在生產環境中,不建議使用萬用字元*來設定Access-Control-Allow-Origin,因為這可能會帶來安全風險。
  • 預檢請求:對於需要傳送額外頭資訊(如自定義頭)或使用非簡單方法(如PUT、DELETE等)的請求,伺服器必須正確處理OPTIONS預檢請求。
  • 憑證支援:如果需要跨域請求時攜帶cookies或認證資訊,確保伺服器設定了Access-Control-Allow-Credentials: true,並且前端請求時需要使用withCredentials: true

透過上述方法,可以解決開發過程中遇到的CORS限制問題。

nginx 是如何支援 CORS 設定的?

Nginx 是一個流行的 Web 伺服器和反向代理伺服器,它可以透過配置檔案來支援 CORS 設定。

以下是如何在 Nginx 配置檔案中設定 CORS 的一些示例。

基本 CORS 設定

如果你想允許所有來源的跨域請求,可以在 Nginx 配置檔案中新增以下行:

location / {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Max-Age' 1728000;
}

允許特定來源的 CORS 設定

如果只想允許特定的域名進行跨域請求,可以將 * 替換為具體的域名:

location / {
    add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Max-Age' 1728000;
}

處理預檢請求

對於需要預檢的請求(如帶有自定義頭或使用非簡單HTTP方法的請求),Nginx 需要正確響應 OPTIONS 請求:

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
    add_header 'DAV' 1;
    return 204;
}

應用到特定路徑

你可以將 CORS 設定應用到特定的路徑或位置塊:

location /api/ {
    add_header 'Access-Control-Allow-Origin' 'https://www.example.com';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Max-Age' 1728000;
}

注意事項

  • 確保 CORS 相關的 add_header 指令在 Nginx 配置檔案的適當位置,通常是在 serverlocation 塊中。
  • 根據你的應用需求,可能需要調整 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 的值。
  • 如果你的應用需要處理預檢請求,確保正確配置 OPTIONS 請求的處理。
  • 重啟 Nginx 服務以使配置更改生效。

透過這些配置,Nginx 可以支援跨源資源共享,從而允許前端應用從不同的源安全地請求後端服務。

小結

本節我們實現了 cors,這個對於瀏覽器安全和日常開發幫助比較大。

我們給出了常見的解決方案,不過實際生產注意使用安全。

下一節,我們考慮實現一下 cors 的支援。

我是老馬,期待與你的下次重逢。

開源地址

為了便於大家學習,已經將 nginx 開源

https://github.com/houbb/nginx4j

相關文章