什么是同源策略?怎樣去解決跨域問題?
時間:2023-09-11 來源:華清遠見
什么是同源策略
同源策略/SOP(Same origin policy)是一種約定,由 Netscape 公司 1995 年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,現在所有支持 JavaScript 的瀏覽器都會使用這個策略。
同源策略可防止 JavaScript 發起跨域請求。源被定義為協議(protocol)、域名(port)、端口(host)的組合,三個要素缺一不可。
看下面的比較一目了然:

不同源的客戶端腳本在沒有明確授權的情況下是不允許讀寫其他網站的資源
同源策略的限制:
Cookie、LocalStorage 和 IndexDB 會話存儲無法讀取
DOM無法獲得
AJAX請求不能發送
同源策略的作用:
防止惡意網站可以回去其他網站的時候,獲取數據
防止惡意網站 ifame其他網站的時候,獲取數據
防止惡意網站在自己網站有訪問其他網站的權利,一面通過 cookie 免登,拿到數據
總的來說同源策略的作用就是限制來自另一個域的資源交互,從而保障我們網站的隱私和數據的安全。
安全性和可用性:
瀏覽器在安全性和可用性之間做了取舍。對于小項目來說,我們把所有的資源都放在自有服務器上面。對于中大型項目來說,由于服務器價格比較貴,我們項目的靜態資源文件,像圖片、視頻等,需要托管在第三方來消減運營成本,所以瀏覽器在遵循安全性的基礎上,放寬了限制,允許img、script、style標簽進行跨域引用資源
那么我們還有其他的方式來解決跨域嗎,我們接著往下看
怎樣去解決跨域問題
跨域產生的原因:
這這里就不過多贅述了,在上面已經提到了,總體的說就是:一個域名想去訪問另一個域名下的資源,但是因為同源策略不同的原因,產生了跨域。所以瀏覽器阻止了訪問
那么我的請求是否發出去了?
跨域并不是請求發不出去,請求時可以發出去的,服務端能收到請求也能正常返回結果,只是結果被瀏覽器攔截了
跨域的解決方案:
1、Jsonp
1)JSONP原理
利用 <script> 標簽沒有跨域限制的漏洞,網頁可以得到從其他來源動態產生的 JSON 數據。JSONP請求一定需要對方的服務器做支持才可以
2)JSONP和AJAX對比
JSONP和AJAX相同,都是客戶端向服務器端發送請求,從服務器端獲取數據的方式。但AJAX屬于同源策略,JSONP屬于非同源策略(跨域請求)
3)JSONP的優缺點
JSONP優點是簡單兼容性好,可用于解決主流瀏覽器的跨域數據訪問的問題。缺點是僅支持get方法具有局限性,不安全可能會遭受XSS攻擊。
在開發中可能會遇到多個 JSONP 請求的回調函數名是相同的,這時候就需要自己封裝一個 JSONP函數

上面這段代碼相當于向//localhost:3000/say?wd=hello&callback=show這個地址請求數據,然后后臺返回show('hello test'),最后會運行show()這個函數,打印出'hello test'

jQuery的jsonp形式

2、Cors
CORS 需要瀏覽器和后端同時支持。IE 8 和 9需要通過 XDomainRequest 來實現。
瀏覽器會自動進行 CORS 通信,實現 CORS 通信的關鍵是后端。只要后端實現了 CORS,就實現了跨域。
服務端設置 Access-Control-Allow-Origin 就可以開啟 CORS。 該屬性表示哪些域名可以訪問資源,如果設置通配符則表示所有網站都可以訪問資源。
雖然設置 CORS 和前端沒什么關系,但是通過這種方式解決跨域問題的話,會在發送請求時出現兩種情況,分別為簡單請求和復雜請求
1)簡單請求
只要同時滿足兩個條件就屬于簡單請求
條件1:使下面方法其中一個
· GET
· HEAD
· POST
條件2:Content-Type 的值僅限于下面三個之一
· text/plain
· multipart/form-data
· application/x-www-form-urlencoded
2)復雜請求
不符合以上條件的請求就肯定是復雜請求了。
復雜請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求,該請求是 option 方法的,通過該請求來知道服務端是否允許跨域請求
我們用PUT向后臺請求時,屬于復雜請求,后臺需做如下配置

接下來我們看下一個完整復雜請求的例子,并且介紹下CORS請求相關的字段



上述代碼由//localhost:3000/index.html向//localhost:4000/跨域請求,正如我們上面所說的,后端是實現 CORS 通信的關鍵
3.Node中間件代理
實現原理:同源策略是瀏覽器需要遵循的標準,而如果是服務器向服務器請求就無需遵循同源策略。代理服務器,需要做以下幾個步驟:
· 接受客戶端請求 。
· 將請求 轉發給服務器。
· 拿到服務器 響應 數據。
· 將響應轉發給客戶端。

舉個例子:本地文件index.html文件,通過代理服務器//localhost:3000向目標服務器//localhost:4000請求數據。



上述代碼經過兩次跨域,值得注意的是瀏覽器向代理服務器發送請求,也遵循同源策略,最后在index.html文件打印出{"title":"你好","password":"111111"}
4.nginx反向代理
實現原理類似于Node中間件代理,需要你搭建一個中轉nginx服務器,用于轉發請求。 使用nginx反向代理實現跨域,是最簡單的跨域方式。只需要修改nginx的配置即可解決跨域問題,支持所有瀏覽器,支持session,不需要修改任何代碼,并且不會影響服務器性能
實現思路:通過nginx配置一個代理服務器(域名與domain1相同,端口不同)做跳板機,反向代理訪問domain2接口,并且可以順便修改cookie中domain信息,方便當前域cookie寫入,實現跨域登錄。
先下載nginx,然后將nginx目錄下的nginx.conf修改如下:



總結:
CORS支持所有類型的HTTP請求,是跨域HTTP請求的根本解決方案
JSONP只支持GET請求,JSONP的優勢在于支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
不管是Node中間件代理還是nginx反向代理,主要是通過同源策略對服務器不加限制。
日常工作中,用得比較多的跨域方案是cors和nginx反向代理

