Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
????????????此賬號為華為云開發者社區官方運營賬號,提供全面深入的云計算前景分析、豐富的技術干貨、程序樣例,分享華為云前沿資訊動態
本文分享自華為云社區《Web安全和瀏覽器跨域訪問》,原文作者:kg-follower 。
今天說一說和前端相關的 Web 安全問題和開發過程中經常遇到的跨域問題。
基本原理
XSS(Cross-Site Scripting),跨站腳本攻擊通過在用戶的瀏覽器內運行非法的 HTML 標簽或 JavaScript 進行的一種攻擊。
攻擊手段
攻擊者往 Web 頁面里插入惡意網頁腳本代碼,當用戶瀏覽該頁面時,嵌入 Web 頁面里面的腳本代碼會被執行,從而達到攻擊者盜取用戶信息或其他侵犯用戶安全隱私的目的。
XSS 攻擊分類
反射型 xss 攻擊。通過給被攻擊者發送帶有惡意腳本的 URL 或將不可信內容插入頁面,當 URL 地址被打開或頁面被執行時,瀏覽器解析、執行惡意腳本。
反射型 xss 的攻擊步驟:1. 攻擊者構造出特殊的 URL 或特殊數據;2. 用戶打開帶有惡意代碼的 URL 時,Web 服務器將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器;3. 用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行;4. 惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行為,調用目標網站接口執行攻擊者指定的操作。
防御:1.Web 頁面渲染的所有內容或數據都必須來自服務端;2. 客戶端對用戶輸入的內容進行安全符轉義,服務端對上交內容進行安全轉義;3.避免拼接 html。
存儲型 xss。惡意腳本被存儲在目標服務器上。當瀏覽器請求數據時,腳本從服務器傳回瀏覽器去執行。
存儲型 xss 的攻擊步驟:1. 攻擊者將惡意代碼提交到目標網站的數據庫中;2.用戶瀏覽到目標網站時,前端頁面獲得數據庫中讀出的惡意腳本時將其渲染執行。
防御:防范存儲型 XSS 攻擊,需要我們增加字符串的過濾:前端輸入時過濾;服務端增加過濾;前端輸出時過濾。
通常有三種方式防御 XSS 攻擊:1. ContentSecurity Policy(CSP)。CSP 本質上就是建立白名單,開發者明確告訴瀏覽器哪些外部資源可以加載和執行。我們只需要配置規則,如何攔截是由瀏覽器自己實現的。我們可以通過這種方式來盡量減少 XSS 攻擊。通常可以通過兩種方式開啟,例如只允許加載相同域下的資源:
設置 HTTP Header 中的 CSP(Content-Security-Policy: default-src 'self')
設置 meta 標簽的方式(<meta http-equiv="Content-Security-Policy"content="form-action 'self';">)
轉義字符
用戶的輸入永遠不可信任的,最普遍的做法就是轉義輸入輸出的內容,對于引號、尖括號、斜杠進行轉義:
function escape(str) {
str=str.replace(/&/g, '&')
str=str.replace(/</g, '<')
str=str.replace(/>/g, '>')
str=str.replace(/"/g, '&quto;')
str=str.replace(/'/g, ''')
str=str.replace(/`/g, '`')
str=str.replace(/\//g, '/')
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><script>alert("xss");</script>
經過白名單過濾,dom 中包含的<script>標簽將不會被執行。
HTTP-only Cookie
禁止 JavaScript 讀取某些敏感 cookie,使得 cookie 只有 http 能夠訪問。
基本概念
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 校驗不成功,那么就拒絕該請求。
DNS 劫持
DNS 劫持就是通過劫持了 DNS 服務器,通過某些手段來取得某個域名的解析控制權,進而修改此域名的解析結果,導致對該域名的訪問由原 IP 地址轉入到修改后的 IP,其結果就是對特定的網站不能訪問或訪問的是假網址。
防御:使用 https 校驗通信雙方身份和數據完整性。
點擊劫持
攻擊者構建了一個非常有吸引力的網頁,將被攻擊的頁面放置在當前頁面的 iframe 中,使用樣式將 iframe 疊加到非常有吸引力內容的上方,將 iframe 設置為 100%透明,其實就是通過覆蓋不可見的頁面,誘導用戶點擊而造成的攻擊行為。
防御措施。1. X-FRAME-OPTIONS 設置允許 iframe 加載的域 2. 限制 iframe 頁面中的 JavaScript 腳本執行。
無論是 xss、csrf 還是點擊劫持,上面討論的這幾種攻擊屬于前端攻擊,原因大多是開發者的腳本或模板代碼存在不安全的隱患或是沒有考慮網絡傳輸安全問題。下面簡單說一說惡意攻擊利用網站后臺漏洞發起的攻擊。
SQL 注入漏洞存在的原因,就是拼接 SQL 參數。也就是將用于輸入的查詢參數,直接拼接在 SQL 語句中,惡意攻擊者可以構造特殊的 sql 語句繞過安全驗證。
SQL 注入條件:1.攻擊者可以控制輸入的數據;2.服務器要執行的代碼拼接了被控制的數據。
SQL 注入防御。1. 嚴格限制 Web 應用的數據庫的操作權限;2. 對進入數據庫的特殊字符(’,”,,<,>,&,*,; 等)進行轉義處理,或編碼轉換,類似防御 xss 攻擊時對輸入轉義;3. 所有的查詢語句建議使用數據庫提供的參數化查詢接口,如使用占位參數或對象關系映射 ORM。
DOS 攻擊通過在網站的各個環節進行攻擊,使得整個流程跑不起來,以達到癱瘓服務為目的。最常見的就是發送大量請求導致服務器過載宕機。DDOS 攻擊的原理就是利用分布式的客戶端,向目標發起大量看上去合法的請求,消耗/占用大量資源,從而達到拒絕服務的目的。
攻擊方式:1.端口掃描;2.ping 洪水;3.SYN 洪水;4.FTP 跳轉攻擊;
DDOS 防范。1.在服務器上刪除未使用的服務,關閉未使用的端口。2. 進行實時監控,封禁某些惡意密集型請求 IP 段;3. 進行靜態資源緩存,隔離源文件的訪問,比如 CDN 加速;4. 隱藏服務器的真實 IP 地址
同源策略是一個重要的安全策略,它用于限制一個源的文檔或者它加載的腳本如何能與另一個源的資源進行交互。它能幫助阻隔惡意文檔,減少可能被攻擊的媒介。所謂同源是指“協議+域名+端口”三者均相同。
同源策略限制了客戶端 js 代碼的以下行為:
1.Cookie、LocalStorage 和 IndexDB 無法讀取;
2.DOM 節點。來自一個源的 js 只能讀寫自己源的 DOM 樹不能讀取其他源的 DOM 樹。如果兩個網頁不同源,就無法拿到對方的 DOM。典型的例子是 iframe 窗口和 window.open 方法打開的窗口,它們與父窗口無法通信。
網站不開啟同源策略,釣魚網站便可以使用 iframe 標簽加載中國銀行登錄界面,執行腳本進而拿到用戶名密碼。
當設置了同源策略,父子窗口執行獲取對方 DOM 時會報錯。
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"
},
--host0.0.0.0 表示監聽所有來源的主機。解決
點擊關注,第一時間了解華為云新鮮技術~
最近在項目上有個移動端(uni-app)的需求,就是要在移動端APP上的vue頁面中通過web-view組件來調用html頁面,并且要實現在html頁面中可以點擊一個元素來調用vue頁面中uni的API(掃碼接口),同時也可以在vue頁面中也可以調用html頁面中的js函數并進行傳參。
1. HBuilderX版本:2.8.11.20200907
2. V3編譯器
引用依賴的文件
在 web-view 加載的 HTML 中調用 uni 的 API,需要在 HTML 中引用必要的 JS-SDK
<script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>
注意:這些 JS 文件是在 web-view 加載的那個 HTML 文件中引用的,而不是 uni-app 項目中的文件。
監聽 web-view 的 message 事件
監聽 web-view 組件的 message 事件,然后在事件回調的 event.detail.data 中接收傳遞過來的消息。
<template>
<view>
<web-view src="http://192.168.1.1:3000/test.html" @message="handleMessage"></web-view>
</view>
</template>
<script>
export default {
methods: {
handleMessage(evt) {
console.log('接收到的消息:' + JSON.stringify(evt.detail.data));
}
}
}
</script>
調用的時機
在引入上面的依賴文件后,需要在HTML中監聽UniAppJSBridgeReady,事件觸發后,
才能安全調用uni的API。
<script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>
<script>
document.querySelector('.btn-list').addEventListener('click', function(evt) {
var target=evt.target;
if (target.tagName==='BUTTON') {
var action=target.getAttribute('data-action');
if(action==='navigateTo') {
uni.postMessage({
data: {
action: 'postMessage'
}
});
}
}
});
</script>
上面代碼的意思就是在html頁面中點擊按鈕列表中的某個按鈕,
觸發了uni.postMessage接口,進而調用了vue頁面methods中的handleMessage方法,
并將參數data傳給了vue頁面。
在vue頁面中調用html頁面的js函數
示例代碼:
var currentWebview=this.$mp.page.$getAppWebview().children()[0];
currentWebview.evalJS("htmljsfuc('"+res.result+"')");
其中的htmljsfuc就是要在html頁面中定義的js函數。
完整代碼示例:
午接到博客訪客的反饋,表示博客中的鏈接在原窗口打開的話,網站的體驗非常的不好,而自己又懶的一個個去修改博客網頁中的鏈接打開方式,就加了一個強制頁面所有鏈接新窗口打開的代碼,一招解決問題。
<base target="_blank">
將此代碼放到,網頁中的 <head>標簽之內即可實現,當前頁面所有A鏈接新窗口打開
<base>:標簽當前頁面上的所有的相對鏈接規定默認 URL 或 默認目標。
語法:
<base href="網址" target="打開的方式">
屬性;
herf:規定的默認鏈接
target:鏈接打開的方式,參數有 _blank,_self 等,與A標簽的 target 屬性相同
<base target="_blank">
<base target="_self">
<!DOCTYPE html> <html lang="en"> <head> <base href="https://www.feiniaomy.com" target="_blank"> <title>Document</title> </head> <body> <a href="/post/1.html">我是相對鏈接,我可以打開 https://www.feiniaomy.com/post/1.html</a> <a href="http://www.baidu.com">我是絕對鏈接,我可以打開 http://www.baidu.com</a> </body> </html>
1、一個頁面中,<base> 標簽只能出現一次
2、<base> 標簽只能在 <head></head>標簽中出現
3、<base> 屬于單標簽,沒有結束標簽,類似 <img> 標簽
*請認真填寫需求信息,我們會在24小時內與您取得聯系。