詳解瀏覽器跨域訪問的幾種辦法


摘要: 本文討論web前端安全問題以及應對措施,瀏覽器同源策略以及對資源跨域訪問的幾種解決方案

本文分享自華為雲社區《Web安全和瀏覽器跨域訪問》,原文作者:kg-follower   。

今天說一說和前端相關的Web安全問題和開發過程中經常遇到的跨域問題。

1.Web安全

1.1 XSS

基本原理

XSS (Cross-Site Scripting),跨站腳本攻擊通過在用戶的瀏覽器內運行非法的HTML標簽或JavaScript進行的一種攻擊。

攻擊手段

攻擊者往 Web 頁面里插入惡意網頁腳本代碼,當用戶瀏覽該頁面時,嵌入 Web 頁面里面的腳本代碼會被執行,從而達到攻擊者盜取用戶信息或其他侵犯用戶安全隱私的目的。

XSS攻擊分類

反射型xss攻擊。通過給被攻擊者發送帶有惡意腳本的URL或將不可信內容插入頁面,當URL地址被打開或頁面被執行時,瀏覽器解析、執行惡意腳本。

反射型xss的攻擊步驟:1. 攻擊者構造出特殊的 URL或特殊數據;2. 用戶打開帶有惡意代碼的 URL 時,Web服務器將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器;3. 用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行;4. 惡意代碼竊取用戶數據並發送到攻擊者的網站,或者冒充用戶的行為,調用目標網站接口執行攻擊者指定的操作。

https://bbs-img.huaweicloud.com/blogs/img/1622251430208002188.png

防御:1.Web頁面渲染的所有內容或數據都必須來自服務端;2. 客戶端對用戶輸入的內容進行安全符轉義,服務端對上交內容進行安全轉義;3.避免拼接html。

存儲型xss。惡意腳本被存儲在目標服務器上。當瀏覽器請求數據時,腳本從服務器傳回瀏覽器去執行。

https://bbs-img.huaweicloud.com/blogs/img/1622251471556019926.png

存儲型xss的攻擊步驟:1. 攻擊者將惡意代碼提交到目標網站的數據庫中;2.用戶瀏覽到目標網站時,前端頁面獲得數據庫中讀出的惡意腳本時將其渲染執行。

防御:防范存儲型XSS攻擊,需要我們增加字符串的過濾:前端輸入時過濾;服務端增加過濾;前端輸出時過濾。

通常有三種方式防御XSS攻擊:1. Content Security Policy(CSP)。CSP 本質上就是建立白名單,開發者明確告訴瀏覽器哪些外部資源可以加載和執行。我們只需要配置規則,如何攔截是由瀏覽器自己實現的。我們可以通過這種方式來盡量減少 XSS 攻擊。通常可以通過兩種方式開啟,例如只允許加載相同域下的資源:

設置 HTTP Header 中的 CSP(Content-Security-Policy: default-src 'self')

設置meta 標簽的方式(<meta http-equiv="Content-Security-Policy" content="form-action 'self';">)

2. 轉義字符。用戶的輸入永遠不可信任的,最普遍的做法就是轉義輸入輸出的內容,對於引號、尖括號、斜杠進行轉義:

function escape(str) {
  str = str.replace(/&/g, '&amp;')
  str = str.replace(/</g, '&lt;')
  str = str.replace(/>/g, '&gt;')
  str = str.replace(/"/g, '&quto;')
  str = str.replace(/'/g, '&#39;')
  str = str.replace(/`/g, '&#96;')
  str = str.replace(/\//g, '&#x2F;')
  return str
}

但是對於顯示富文本來說,顯然不能通過上面的辦法來轉義所有字符,因為這樣會把需要的格式也過濾掉。對於這種情況,通常采用白名單過濾的辦法:

const xss = require('xss')
let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
console.log(html)
<h1>XSS Demo</h1>&lt;script&gt;alert("xss");&lt;/script&gt;

經過白名單過濾,dom中包含的<script>標簽將不會被執行。

HTTP-only Cookie: 禁止 JavaScript 讀取某些敏感 cookie,使得 cookie只有http能夠訪問。

1.2 CSRF

基本概念

CSRF(Cross-site request forgery跨站請求偽造:攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送跨站請求。利用受害者在被攻擊網站已經獲取的注冊憑證,繞過后台的用戶驗證,達到冒充用戶對被攻擊的網站執行某項操作的目的。

CSRF攻擊類型

主動型攻擊。用戶訪問網站A並在瀏覽器保存A的登錄狀態(cookie等信息),攻擊者誘導受害者訪問網站B,網站B含有訪問A接口的惡意代碼,受害者訪問B時帶着A的登錄狀態,攻擊者便可以冒充用戶執行對A的惡意操作。

被動型攻擊。攻擊者在網站A發布帶有惡意鏈接的評論或內容(提交對A帶有增刪改的誘導型標簽),當其他擁有登錄狀態的受害者點擊評論的惡意鏈接時,就會冒用受害者登錄憑證發起攻擊。

CSRF攻擊防范

驗證HTTP Referer字段。在HTTP頭中有Referer字段,他記錄該HTTP請求的來源地址,如果跳轉的網站與來源地址相符,那就是合法的,如果不符則可能是csrf攻擊,拒絕該請求。

SameSite。可以對 Cookie 設置 SameSite 屬性。該屬性表示 Cookie 不隨着跨域請求發送,可以很大程度減少 CSRF 的攻擊。

請求中加入token。服務端給用戶生成一個token,加密后傳遞給用戶,用戶在提交請求時,需要攜帶這個token,服務端發現token不存在或者token校驗不成功,那么就拒絕該請求。

1.3 流量劫持

DNS劫持

DNS劫持就是通過劫持了DNS服務器,通過某些手段來取得某個域名的解析控制權,進而修改此域名的解析結果,導致對該域名的訪問由原IP地址轉入到修改后的IP,其結果就是對特定的網站不能訪問或訪問的是假網址。

防御:使用https校驗通信雙方身份和數據完整性。

點擊劫持

https://bbs-img.huaweicloud.com/blogs/img/1622259924230001347.png

攻擊者構建了一個非常有吸引力的網頁,將被攻擊的頁面放置在當前頁面的 iframe 中,使用樣式將 iframe 疊加到非常有吸引力內容的上方,將iframe設置為100%透明,其實就是通過覆蓋不可見的頁面,誘導用戶點擊而造成的攻擊行為。

防御措施。1. X-FRAME-OPTIONS設置允許iframe加載的域    2. 限制iframe頁面中的JavaScript腳本執行。

無論是xss、csrf還是點擊劫持,上面討論的這幾種攻擊屬於前端攻擊,原因大多是開發者的腳本或模板代碼存在不安全的隱患或是沒有考慮網絡傳輸安全問題。下面簡單說一說惡意攻擊利用網站后台漏洞發起的攻擊。

1.4 SQL注入

SQL 注入漏洞存在的原因,就是拼接 SQL 參數。也就是將用於輸入的查詢參數,直接拼接在 SQL 語句中,惡意攻擊者可以構造特殊的sql語句繞過安全驗證。

SQL注入條件:1.攻擊者可以控制輸入的數據;2.服務器要執行的代碼拼接了被控制的數據。

SQL注入防御。1. 嚴格限制Web應用的數據庫的操作權限;2. 對進入數據庫的特殊字符(’,”,,<,>,&,*,; 等)進行轉義處理,或編碼轉換,類似防御xss攻擊時對輸入轉義;3. 所有的查詢語句建議使用數據庫提供的參數化查詢接口,如使用占位參數或對象關系映射ORM。

1.5 DDOS攻擊

DOS攻擊通過在網站的各個環節進行攻擊,使得整個流程跑不起來,以達到癱瘓服務為目的。最常見的就是發送大量請求導致服務器過載宕機。DDOS攻擊的原理就是利用分布式的客戶端,向目標發起大量看上去合法的請求,消耗/占用大量資源,從而達到拒絕服務的目的。

攻擊方式:1.端口掃描;2.ping洪水;3.SYN洪水;4.FTP跳轉攻擊;

DDOS防范。1.在服務器上刪除未使用的服務,關閉未使用的端口。2. 進行實時監控,封禁某些惡意密集型請求IP段;3. 進行靜態資源緩存,隔離源文件的訪問,比如CDN加速;4. 隱藏服務器的真實IP地址

3 跨域和同源策略

同源策略是一個重要的安全策略,它用於限制一個源的文檔或者它加載的腳本如何能與另一個源的資源進行交互。它能幫助阻隔惡意文檔,減少可能被攻擊的媒介。所謂同源是指“協議+域名+端口”三者均相同。

同源策略限制了客戶端js代碼的以下行為:

1.Cookie、LocalStorage 和 IndexDB 無法讀取;

2.DOM節點。來自一個源的js只能讀寫自己源的DOM樹不能讀取其他源的DOM樹。如果兩個網頁不同源,就無法拿到對方的DOM。典型的例子是iframe窗口和window.open方法打開的窗口,它們與父窗口無法通信。

網站不開啟同源策略,釣魚網站便可以使用iframe標簽加載中國銀行登錄界面,執行腳本進而拿到用戶名密碼。

當設置了同源策略,父子窗口執行獲取對方DOM時會報錯。

https://bbs-img.huaweicloud.com/blogs/img/1622260138253095590.png

 

 

 

 

 

 

 

 

 

 

 

3.AJAX請求限制

跨域並不是請求發不出去,請求能發出去,服務端能收到請求並正常返回結果,只是結果被瀏覽器攔截了。

除了架設服務器代理,還有以下幾種方法規避同源限制:JSONP,WebSocket,CORS,本文詳細討論下后兩種方法的實現。

WebSocket。WebSocket是一種通信協議,使用ws://(非加密)和wss://(加密)作為協議前綴。該協議不實行同源政策,只要服務器支持,就可以通過它進行跨源通信。WebSocket 是一種雙向通信協議,在建立連接之后,WebSocket 的 server 與 client 都能主動向對方發送或接收數據。Websocket請求頭信息包含一個origin字段,服務器根據這個字段判斷是否允許本次通信。

CORS。CORS跨域資源共享是W3C標准,是解決跨域Ajax請求的最常見解決方法。整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。

瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。只要同時滿足以下兩大條件,就屬於簡單請求:

(1) 請求方法是以下三種方法之一:HEAD、GET、POST  

(2)HTTP的頭信息不超出以下幾種字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭信息之中,增加一個Origin字段,該字段用來說明,本次請求來自哪個源。服務器根據這個值,決定是否同意這次請求。如果Origin指定的源,不在許可范圍內,服務器會返回一個正常的HTTP回應。若該響應的頭信息沒有包含Access-Control-Allow-Origin字段,就拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。若Origin指定的域名在許可范圍內,服務器返回的響應,會多出幾個頭信息字段。其中Access-Control-Allow-Origin字段是必須的。它的值要么是請求時Origin字段的值,要么是一個*,表示接受任意域名的請求。

對於非簡單請求,在正式通信之前,會增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP方法和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。

"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭信息里面,關鍵字段是Origin,表示請求來自哪個源。

除了Origin字段,"預檢"請求的頭信息包括兩個特殊字段。

(1)Access-Control-Request-Method。該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法

(2)Access-Control-Request-Headers。該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段。

預檢請求的回應。

服務器收到"預檢"請求以后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認允許跨源請求,就可以做出回應。回應最關鍵的是Access-Control-Allow-Origin字段,表示允許該源的請求,若沒有任何CORS相關頭信息字段則說明服務器否認該請求。若服務器允許,則Access-Control-Allow-Methods字段是必須的,它的值是一個逗號分隔的字符串,表明服務器支持的方法。如果預檢請求包含Access-Control-Request-Headers字段,則返回體中該字段也是必須的,它也是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限於瀏覽器在"預檢"中請求的字段。預檢請求得到允許回應后,瀏覽器便發送正常CORS請求。

最近在開發一個前端poc項目時遇到了跨域資源訪問被限制的問題,在本地啟動angular項目,其他人可以通過ip訪問到靜態資源,發送ajax請求時被限制。於是想通過配置代理的方式解決這個跨域問題:在和package.json同級的目錄中新建proxy.conf.json文件,target字段是后端服務真實的ip,changeOrigin字段設置為true,關閉secure字段。

{
    "/": {
      "target": "http://10.173.99.224:8081/",
      "changeOrigin": true,
      "secure": false,
      "loglevel": "debug"
    }
}

在package.json的啟動命令中添加

 
"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.conf.json --host 0.0.0.0",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },

--host 0.0.0.0 表示監聽所有來源的主機。解決

 

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM