主頁 > 企業開發 > 15 張精美動圖全面講解 CORS

15 張精美動圖全面講解 CORS

2020-09-13 01:22:04 企業開發

前言:

本文翻譯自 Lydia Hallie 小姐姐寫的 ????? CS Visualized: CORS,她用了大量的動圖去解釋 CORS 這個概念,國內還沒有人翻譯本文,所以我在原文的理解上翻譯了本文并修改了一些錯誤,希望能幫到大家,

覺得翻譯的不錯一定要點贊哦,謝謝你,這對我真的很重要! ??

注:原文的動圖均為 keynote 制作



前端開發中,我們經常要使用其他站點的資料,前端顯示這些資料之前,必須向服務器發出請求以獲取該資料,

假設我們正在訪問 https://api.mywebsite.com 這個站點,點擊按鈕向 https://api.mywebsite.com/users 發送請求,獲取網站上的一些用戶資訊:

??:這里原作者有個筆誤,把 https://api.mywebsite.com 誤寫為 https://www.mywebsite.com 了,圖中也有這個錯誤,讀者要注意一下不要被誤導

從結果上看表現非常完美,我們向服務器發送請求,服務器回傳了我們需要的 JSON 資料,前端也正常的渲染出了結果,

下面我們換一個網站試試,用 https://www.anotherwebsite.com 這個網站向 https://api.website.com/users 發送請求:

問題來了,我們請求同樣的介面網站,但是這次瀏覽器給我們拋出一個 Error,

剛剛瀏覽器拋出的就是 CORS Error,下面讓我們分析一下為什么會產生這種 Error,以及這個 Error 的確切含義是什么,

1.同源策略

瀏覽器網路請求時,有一個同源策略的機制,即默認情況下,使用 API 的 Web 應用程式只能從加載應用程式的同一個域請求 HTTP 資源,

比如說, https://www.mywebsite.com 請求 https://www.mywebsite.com/page 是完全沒有問題的,但是當資源位于不同協議子域的站點時,這個請求就是跨域的,

目前來看,同源策略會讓三種行為受限:

  • Cookie、LocalStorage 和 IndexDB 訪問受限
  • 無法操作跨域 DOM(常見于 iframe)
  • Javascript 發起的 XHR 和 Fetch 請求受限

那么,為什么會存在同源策略呢?

我們做個假設,如果不存在同源策略,你無意中點擊了七大姑在微信上給你發的一篇養生文章鏈接,其實這個網頁是個釣魚網站,訪問鏈接后就把你重定向到一個嵌入了 iframe 的攻擊網站,這個 iframe 會自動加載銀行網站,并通過 cookies 登錄你的賬戶,

登陸成功后,這個釣魚網站還可以控制 iframe 的 DOM,通過一系列騷操作把你卡里的錢轉走,

這是一個非常嚴重的安全漏洞,我們不希望自己在互聯網的內容被隨便訪問,更不要說這種涉及到錢的網站了,

同源策略可以幫助我們解決這個安全問題,這個策略確保我們只能訪問同一站點的資源,

在這種情況下,https://www.evilwebsite.com 嘗試跨站訪問 https://www.bank.com 的資源,同源策略就會阻止這個操作,讓釣魚網站無法訪問銀行網站的資料,

說了這么多,同源策略和 CORS 又有什么關系?

2.瀏覽器 CORS

出于安全原因,瀏覽器限制從腳本內發起的跨域 HTTP 請求, 例如 XHR 和 Fetch 就遵循同源策略,這意味著使用 API 的 Web 應用程式只能從加載應用程式的同一個域請求 HTTP 資源,

日常的業務開發中,我們會經常訪問跨域資源,為了安全的請求跨域資源,瀏覽器使用一種稱為 CORS 的機制,

CORS 的全名是 Cross-Origin Resource Sharing,即跨域資源共享,盡管默認情況下瀏覽器禁止我們訪問跨域資源,但是我們可以利用 CORS 放寬這種限制,在保證安全性的前提下訪問跨域資源,

瀏覽器可以利用 CORS 機制,放行符合規范的跨域訪問,阻止不合規范的跨域訪問,瀏覽器內部是怎么做的呢?我們下面就來分析一下,

Web 程式發出跨域請求后,瀏覽器會自動向我們的 HTTP header 添加一個額外的請求頭欄位:OriginOrigin 標記了請求的站點來源:

GET https://api.website.com/users HTTP/1/1
Origin: https://www.mywebsite.com // <- 瀏覽器自己加的

為了使瀏覽器允許訪問跨域資源, 服務器回傳的 response 還需要加一些回應頭欄位,這些欄位將顯式表明此服務器是否允許這個跨域請求,

3.服務端 CORS

作為服務器開發人員,我們可以通過在 HTTP 回應中添加額外的回應頭欄位 Access-Control-* 來表明是否允許跨域請求,根據這些 CORS 回應頭欄位,瀏覽器可以允許一些被同源策略限制的跨源回應,

雖然有好幾個 CORS 回應頭欄位,但有一個欄位是必加的,那就是 Access-Control-Allow-Origin,這個頭欄位的值指定了哪些站點被允許跨域訪問資源,

1?? 如果我們有服務器的開發權限,我們可以給 https://www.mywebsite.com 加上訪問權限:將該域添加到 Access-Control-Allow-Origin 中,

這個回應頭欄位現在被添加到服務器發回給客戶端的 response header 中,這個欄位添加后,如果我們從 https://www.mywebsite.com 發送跨域請求,同源策略將不再限制 https://api.mywebsite.com 站點回傳的資源,

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.mywebsite.com
Date: Fri, 11 Oct 2019 15:47 GM
Content-Length: 29
Content-Type: application/json
Server: Apache

{user: [{...}]}

2?? 收到服務器回傳的 response 后,瀏覽器中的 CORS 機制會檢查 Access-Control-Allow-Origin 的值是否等于 request 中 Origin 的值,

在這個例子中,request 的 Originhttps://www.mywebsite.com,這和 response 中 Access-Control-Allow-Origin 的值是一樣的:

3?? 瀏覽器校驗通過,前端成功地接收到跨域資源,


那么,當我們試圖從一個沒有在 Access-Control-Allow-Origin 中列出的網站跨域訪問這些資源會發生什么呢?

如上圖所示,從 https://www.anotherwebsite.com 跨域訪問 https://api.mywebsite.com 資源,瀏覽器拋出一個 CORS Error,經過上面的講解,我們可以讀懂這個報錯資訊了:

The 'Access-Control-Allow-Origin' header has a value
 'https://www.mywebsite.com' that is not equal 
to the supplied origin. 

在這種情況下,Origin 的值是 https://www.anotherwebsite.com,然而,服務器在 Access-Control-Allow-Origin 回應頭欄位中沒有標記這個站點,瀏覽器 CORS 機制就阻止了這個回應,我們無法在我們的代碼中獲取回應資料,

CORS 還允許我們添加通配符 * 作為允許的外域,這意味著該資源可以被任意外域訪問,所以要注意這種特殊情況


Access-Control-Allow-Origin 是 CORS 機制提供的眾多頭欄位之一,服務器開發人員還可以通過其它頭欄位擴展服務器的 CORS 策略,以允許/禁止某些請求,

另一個常見的回應頭欄位是 Access-Control-Allow-Methods,其指明了跨域請求所允許使用的 HTTP 方法,

在上圖的案例中,只有GETPOSTPUT 方法被允許跨域訪問資源,其他 HTTP 方法,例如 PATCHDELETE 都會被阻止,

如果您想知道其它的 CORS 回應頭欄位是什么以及它們的用途,可以查看此串列,

說到PUTPATCHDELETE 這幾個 HTTP 方法,CORS 處理這些方法時還有些不同,這些非簡單請求會觸發 CORS 的預檢請求,

4.預檢請求

CORS 有兩種型別的請求:一種是簡單請求(simple request),一種是預檢請求(preflight request),一個跨域請求到底是簡單的的還是預檢的,取決于一些 request header,

當請求是 GETPOST 方法并且沒有任何自定義 Header 欄位時,一般來說就是個簡單請求,除此之外的任何請求,諸如 PUTPATCHDELETE 方法,將會產生預檢,

如果你想知道一個請求必須滿足哪些要求才能成為簡單請求,可以查看 MDN 簡單請求相關的檔案,

說了這么多,「預檢請求」到底是什么意思?下面我們就來探討一下,


1?? 在發送實際請求之前,客戶端會先使用 OPTIONS 方法發起一個預檢請求,預檢請求的 Access-Control-Request-* 中包含有關我們將要處理的實際請求的資訊:

  • 首部欄位 Access-Control-Request-Method 告知服務器,實際請求要用到的方法是什么
  • 首部欄位 Access-Control-Request-Headers 告知服務器,實際請求將附帶的自定義請求首部欄位是什么
OPTIONS https://api.mywebsite.com/user/1 HTTP/1.1
Origin: https://www.mywebsite.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

2?? 服務器接收到預檢請求后,會回傳一個沒有 body 的 HTTP 回應,這個回應標記了服務器允許的 HTTP 方法和 HTTP Header 欄位:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://www.mywebsite.com
Access-Control-Request-Method: GET POST PUT
Access-Control-Request-Headers: Content-Type

3?? 瀏覽器收到預檢回應,并檢查是否應允許發送實際請求,

??:上圖預檢回應漏了 Access-Control-Allow-Headers: Content-Type

4?? 如果預檢回應檢測通過,瀏覽器會將實際請求發送到服務器,然后服務器回傳我們需要的資源,

如果預檢回應沒有檢驗通過,CORS 會阻止跨域訪問,實際的請求永遠不會被發送,預檢請求是一種很好的方式,可以防止我們訪問或修改那些沒有啟用 CORS 策略的服務器上的資源,

?? 為了減少網路往返次數,我們可以通過在 CORS 請求中添加 Access-Control-Max-Age 頭欄位來快取預檢回應,瀏覽器可以使用快取來代替發送新的預檢請求,

5.認證

XHR 或 Fetch 與 CORS 的一個有趣的特性是,我們可以基于 Cookies 和 HTTP 認證資訊發送身份憑證,一般而言,對于跨域 XHR 或 Fetch 請求,瀏覽器不會發送身份憑證資訊,

盡管 CORS 默認情況下不發送身份憑證,但我們可以通過添加 Access-Control-Allow-Credentials CORS 回應頭來更改它,

如果要在跨域請求中包含 cookie 和其他授權資訊,我們需要做以下操作:

  • XHR 請求中將 withCredentials 欄位設定為 true
  • Fetch 請求中將 credentials 設為 include
  • 服務器把 Access-Control-Allow-Credentials: true 添加到回應頭中
// 瀏覽器 fetch 請求
fetch('https://api.mywebsite,com.users', {
  credentials"include"
})

// 瀏覽器 XHR 請求
let xhr = new XMLHttpRequest();
xhr.withCredentials = true;

// 服務器添加認證欄位
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true

把上面的作業做好后,我們就可以在跨域請求中包含身份憑證資訊了,

6.總結

CORS Error 一定程度上會讓前端開發很頭疼,但是遵循它的相關規定后,它可以讓我們在瀏覽器中進行安全的跨域請求,

同源策略和 CORS 的知識點有很多,本文只講了一些關鍵知識點,如果你想全面學習 CORS 的相關知識,我推薦你查閱MDN 檔案和 W3C 規范,這些一手知識是最準確的,

7.最后

這篇文章就到此結束了,如果覺得不錯的話一定要點贊鼓勵一下哦,祝大家學習進步,作業順利!

如果想要學習更多非筆記式的 HTTP 知識,可以看看我之前寫的舊文:

  • X-Forwarded-For 拿到的就是真實 IP 嗎?
  • HTTP 請求中,空格應該被編碼為 %20 還是 + ?
  • HTTP 的這幾個坑你都踩過嗎?

最后推薦一波我的個人號:鹵蛋實驗室(egglabs),會更新一些前端技術與圖形學相關的文章,獨創不灌水,歡迎大家關注,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/18361.html

標籤:JavaScript

上一篇:JAVA 如何訪問sharepoint 檔案庫中檔案內容?

下一篇:浮點數相關

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more