前言:
在當下,數據安全與個人隱私受到了前所未有的挑戰。如何才能更好地保護我們的數據?接下來分析幾種常見的攻擊的類型以及防御的方法。
一、XSS(Cross Site Script)
首先了解最常見的 XSS 漏洞,XSS (Cross Site Script),跨站腳本攻擊,因為縮寫和 CSS (Cascading Style Sheets) 重疊,所以叫 XSS。
XSS 的原理是惡意攻擊者往 Web 頁面里插入惡意可執行網頁腳本代碼,當用戶瀏覽該頁之時,嵌入其中 Web 里面的腳本代碼會被執行,從而可以達到攻擊者盜取用戶信息或其他侵犯用戶安全隱私的目的。
XSS的影響:
1. 利用虛假輸入表單騙取用戶個人信息。
2. 利用腳本竊取用戶的Cookie值,被害者在不知情的情況下,幫助攻擊者發送惡意請求。
3. 顯示偽造的文章或圖片。
XSS 的攻擊方式千變萬化,但還是可以大致細分為幾種類型。
- 非持久化XSS(反射型XSS)
非持久型 XSS 漏洞,一般是通過給別人發送帶有惡意腳本代碼參數的 URL,當 URL 地址被打開時,特有的惡意代碼參數被 HTML 解析、執行。
例如:
Select your language: <select> <script> document.write('' + '<option value=1>' + location.href.substring(location.href.indexOf('default=') + 8) + '</option>' ); document.write('<option value=2>English</option>'); </script> </select>
攻擊者可以直接通過 URL (類似:https://xx.com/xx?default=<script>alert(document.cookie)</script>) 注入可執行的腳本代碼。
非持久化XSS攻擊的特點:
-
- 即時性,不經過服務器存儲,直接通過 HTTP 的 GET 和 POST 請求就能完成一次攻擊,拿到用戶隱私數據。
- 攻擊者需要誘騙點擊
- 反饋率低,所以較難發現和響應修復
- 盜取用戶敏感保密信息
預防方法:
-
- Web 頁面渲染的所有內容或者渲染的數據都必須來自於服務端。
- 盡量不要從 URL,
document.referrer
,document.forms
等這種 DOM API 中獲取數據直接渲染。 - 盡量不要使用
eval
,new Function()
,document.write()
,document.writeln()
,window.setInterval()
,window.setTimeout()
,innerHTML
,document.creteElement()
等可執行字符串的方法。 - 如果做不到以上幾點,也必須對涉及 DOM 渲染的方法傳入的字符串參數做 escape 轉義。
- 前端渲染的時候對任何的字段都需要做 escape 轉義編碼。(escape 轉義的目的是將一些構成 HTML 標簽的元素轉義,比如
<
,>
,空格 等,轉義成<
,>
,
等顯示轉義字符。有很多開源的工具可以協助我們做 escape 轉義)
- 持久化XSS(存儲型 XSS)
持久型 XSS 漏洞,一般存在於 Form 表單提交等交互功能,如文章留言,提交文本信息等,黑客利用的 XSS 漏洞,將內容經正常功能提交進入數據庫持久保存,當前端頁面獲得后端從數據庫中讀出的注入代碼時,恰好將其渲染執行。
例如:評論功能就得防范持久型 XSS 攻擊,因為我可以在評論中輸入以下內容
主要注入頁面方式和非持久型 XSS 漏洞類似,只不過持久型的不是來源於 URL,referer,forms 等,而是來源於后端從數據庫中讀出來的數據 。持久型 XSS 攻擊不需要誘騙點擊,黑客只需要在提交表單的地方完成注入即可,但是這種 XSS 攻擊的成本相對還是很高。
攻擊成功需要同時滿足以下幾個條件:
-
- POST 請求提交表單后端沒做轉義直接入庫。
- 后端從數據庫中取出數據沒做轉義直接輸出給前端。
- 前端拿到后端數據沒做轉義直接渲染成 DOM。
持久型 XSS 有以下幾個特點:
-
- 持久性,植入在數據庫中
- 盜取用戶敏感私密信息
- 危害面廣
防御方式:
1) CSP
CSP 本質上就是建立白名單,開發者明確告訴瀏覽器哪些外部資源可以加載和執行。我們只需要配置規則,如何攔截是由瀏覽器自己實現的。我們可以通過這種方式來盡量減少 XSS 攻擊。
通常可以通過兩種方式來開啟 CSP:
-
- 設置 HTTP Header 中的 Content-Security-Policy
- 設置 meta 標簽的方式
這里以設置 HTTP Header 來舉例:
-
- 只允許加載本站資源:Content-Security-Policy: default-src 'self'
- 只允許加載 HTTPS 協議圖片:Content-Security-Policy: img-src https://*
- 允許加載任何來源框架:Content-Security-Policy: child-src 'none'
如需了解更多屬性,請查看Content-Security-Policy文檔
對於這種方式來說,只要開發者配置了正確的規則,那么即使網站存在漏洞,攻擊者也不能執行它的攻擊代碼,並且 CSP 的兼容性也不錯。
2) 轉義字符
用戶的輸入永遠不可信任的,最普遍的做法就是轉義輸入輸出的內容,對於引號、尖括號、斜杠進行轉義
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>') // -> <h1>XSS Demo</h1><script>alert("xss");</script>
console.log(html)
以上示例使用了 js-xss 來實現,可以看到在輸出中保留了 h1 標簽且過濾了 script 標簽。
3) HttpOnly Cookie。
這是預防XSS攻擊竊取用戶cookie最有效的防御手段。Web應用程序在設置cookie時,將其屬性設為HttpOnly,就可以避免該網頁的cookie被客戶端惡意JavaScript竊取,保護用戶cookie信息。
二、CSRF
CSRF(Cross-Site Request Forgery),中文名稱:跨站請求偽造攻擊;一種常見的Web攻擊,它利用用戶已登錄的身份,在用戶毫不知情的情況下,以用戶的名義完成非法操作。
CSRF原理:
CSRF 攻擊必須要條件:
- 用戶已經登錄了站點 A,並在本地記錄了 cookie
- 在用戶沒有登出站點 A 的情況下(也就是 cookie 生效的情況下),訪問了惡意攻擊者提供的引誘危險站點 B (B 站點要求訪問站點A)。
- 站點 A 沒有做任何 CSRF 防御
防御方式:
防范 CSRF 攻擊可以遵循以下幾種規則:
-
- Get 請求不對數據進行修改
- 不讓第三方網站訪問到用戶 Cookie
- 阻止第三方網站請求接口
- 請求時附帶驗證信息,比如驗證碼或者 Token
1) SameSite
可以對 Cookie 設置 SameSite 屬性。該屬性表示 Cookie 不隨着跨域請求發送,可以很大程度減少 CSRF 的攻擊,但是該屬性目前並不是所有瀏覽器都兼容。
2) Referer Check
HTTP Referer是header的一部分,當瀏覽器向web服務器發送請求時,一般會帶上Referer信息告訴服務器是從哪個頁面鏈接過來的,服務器籍此可以獲得一些信息用於處理。可以通過檢查請求的來源來防御CSRF攻擊。正常請求的referer具有一定規律,如在提交表單的referer必定是在該頁面發起的請求。所以通過檢查http包頭referer的值是不是這個頁面,來判斷是不是CSRF攻擊。
但在某些情況下如從https跳轉到http,瀏覽器處於安全考慮,不會發送referer,服務器就無法進行check了。若與該網站同域的其他網站有XSS漏洞,那么攻擊者可以在其他網站注入惡意腳本,受害者進入了此類同域的網址,也會遭受攻擊。出於以上原因,無法完全依賴Referer Check作為防御CSRF的主要手段。但是可以通過Referer Check來監控CSRF攻擊的發生。
3) Anti CSRF Token
目前比較完善的解決方案是加入Anti-CSRF-Token。即發送請求時在HTTP 請求中以參數的形式加入一個隨機產生的token,並在服務器建立一個攔截器來驗證這個token。服務器讀取瀏覽器當前域cookie中這個token值,會進行校驗該請求當中的token和cookie當中的token值是否都存在且相等,才認為這是合法的請求。否則認為這次請求是違法的,拒絕該次服務。
這種方法相比Referer檢查要安全很多,token可以在用戶登陸后產生並放於session或cookie中,然后在每次請求時服務器把token從session或cookie中拿出,與本次請求中的token 進行比對。由於token的存在,攻擊者無法再構造出一個完整的URL實施CSRF攻擊。但在處理多個頁面共存問題時,當某個頁面消耗掉token后,其他頁面的表單保存的還是被消耗掉的那個token,其他頁面的表單提交時會出現token錯誤。
4) 驗證碼
應用程序和用戶進行交互過程中,特別是賬戶交易這種核心步驟,強制用戶輸入驗證碼,才能完成最終請求。在通常情況下,驗證碼夠很好地遏制CSRF攻擊。但增加驗證碼降低了用戶的體驗,網站不能給所有的操作都加上驗證碼。所以只能將驗證碼作為一種輔助手段,在關鍵業務點設置驗證碼。
三、SQL注入
SQL注入是一種常見的Web安全漏洞,攻擊者利用這個漏洞,可以訪問或修改數據,或者利用潛在的數據庫漏洞進行攻擊。
示例:
前端:
<form action="/login" method="POST"> <p>Username: <input type="text" name="username" /></p> <p>Password: <input type="password" name="password" /></p> <p><input type="submit" value="登陸" /></p> </form>
后端SQL:
string querySQL = $"SELECT sername FROM user WHERE sername='{username}' AND psw='{password}'";
SQL注入的必備條件:
1.可以控制輸入的數據
2.服務器要執行的代碼拼接了控制的數據。
危害
- 獲取數據庫信息
- 管理員后台用戶名和密碼
- 獲取其他數據庫敏感信息:用戶名、密碼、手機號碼、身份證、銀行卡信息……
- 整個數據庫:脫褲
- 獲取服務器權限
- 植入Webshell,獲取服務器后門
- 讀取服務器敏感文件
預防 SQL 注入
防止 SQL 注入主要是不能允許用戶輸入的內容影響正常的 SQL 語句的邏輯,當用戶的輸入的信息將要用來拼接 SQL 語句的話,我們應該永遠選擇不相信,任何內容都必須進行轉義過濾,當然做到這個還是不夠的,下面列出防御 SQL 注入的幾點注意事項:
-
-
嚴格限制Web應用的數據庫的操作權限,給此用戶提供僅僅能夠滿足其工作的最低權限,從而最大限度的減少注入攻擊對數據庫的危害
-
后端代碼檢查輸入的數據是否符合預期,嚴格限制變量的類型,例如使用正則表達式進行一些匹配處理。
-
對進入數據庫的特殊字符(
'
,"
,\
,<
,>
,&
,*
,;
等)進行轉義處理,或編碼轉換。基本上所有的后端語言都有對字符串進行轉義處理的方法,比如 lodash 的lodash._escapehtmlchar
庫。 -
所有的查詢語句建議使用數據庫提供的參數化查詢接口,參數化的語句使用參數而不是將用戶輸入變量嵌入到 SQL 語句中,即不要直接拼接 SQL 語句。例如 Node.js 中的 mysqljs 庫的
query
方法中的?
占位參數。
-
-
-
在應用發布之前建議使用專業的 SQL 注入檢測工具進行檢測,以及時修補被發現的 SQL 注入漏洞。網上有很多這方面的開源工具,例如 sqlmap、SQLninja 等。
-
避免網站打印出 SQL 錯誤信息,比如類型錯誤、字段不匹配等,把代碼里的 SQL 語句暴露出來,以防止攻擊者利用這些錯誤信息進行 SQL 注入。
-
不要過於細化返回的錯誤信息,如果目的是方便調試,就去使用后端日志,不要在接口上過多的暴露出錯信息,畢竟真正的用戶不關心太多的技術細節,只要話術合理就行。
-
四、DDoS攻擊
DDoS 又叫分布式拒絕服務,全稱 Distributed Denial of Service,其原理就是利用大量的請求造成資源過載,導致服務不可用
DDos 攻擊從層次上可分為網絡層攻擊與應用層攻擊,從攻擊手法上可分為快型流量攻擊與慢型流量攻擊,但其原理都是造成資源過載,導致服務不可用。
- 網絡層DDoS
網絡層 DDos 攻擊包括 SYN Flood
、ACK Flood
、UDP Flood
、ICMP Flood
等。
SYN Flood 攻擊
SYN flood 攻擊主要利用了 TCP 三次握手過程中的 Bug,我們都知道 TCP 三次握手過程是要建立連接的雙方發送 SYN,SYN + ACK,ACK 數據包,而當攻擊方隨意構造源 IP 去發送 SYN 包時,服務器返回的 SYN + ACK 就不能得到應答(因為 IP 是隨意構造的),此時服務器就會嘗試重新發送,並且會有至少 30s 的等待時間,導致資源飽和服務不可用,此攻擊屬於慢型 DDoS 攻擊。
ACK Flood 攻擊
ACK Flood 攻擊是在 TCP 連接建立之后,所有的數據傳輸 TCP 報文都是帶有 ACK 標志位的,主機在接收到一個帶有 ACK 標志位的數據包的時候,需要檢查該數據包所表示的連接四元組是否存在,如果存在則檢查該數據包所表示的狀態是否合法,然后再向應用層傳遞該數據包。如果在檢查中發現該數據包不合法,例如該數據包所指向的目的端口在本機並未開放,則主機操作系統協議棧會回應 RST 包告訴對方此端口不存在。
UDP Flood 攻擊
UDP flood 攻擊是由於 UDP 是一種無連接的協議,因此攻擊者可以偽造大量的源 IP 地址去發送 UDP 包,此種攻擊屬於大流量攻擊。正常應用情況下,UDP 包雙向流量會基本相等,因此發起這種攻擊的攻擊者在消耗對方資源的時候也在消耗自己的資源。
ICMP Flood 攻擊
ICMP Flood 攻擊屬於大流量攻擊,其原理就是不斷發送不正常的 ICMP 包(所謂不正常就是 ICMP 包內容很大),導致目標帶寬被占用,但其本身資源也會被消耗。目前很多服務器都是禁 ping 的(在防火牆在可以屏蔽 ICMP 包),因此這種攻擊方式已經落伍。
網絡層DDoS防御
網絡層的 DDoS 攻擊究其本質其實是無法防御的,我們能做得就是不斷優化服務本身部署的網絡架構,以及提升網絡帶寬。當然,還是做好以下幾件事也是有助於緩解網絡層 DDoS 攻擊的沖擊:
-
- 網絡架構上做好優化,采用負載均衡分流。
- 確保服務器的系統文件是最新的版本,並及時更新系統補丁。
- 添加抗 DDos 設備,進行流量清洗。
- 限制同時打開的 SYN 半連接數目,縮短 SYN 半連接的 Timeout 時間。
- 限制單 IP 請求頻率。
- 防火牆等防護設置禁止 ICMP 包等。
- 嚴格限制對外開放的服務器的向外訪問。
- 運行端口映射程序或端口掃描程序,要認真檢查特權端口和非特權端口。
- 關閉不必要的服務。
- 認真檢查網絡設備和主機/服務器系統的日志。只要日志出現漏洞或是時間變更,那這台機器就可能遭到了攻擊。
- 限制在防火牆外與網絡文件共享。這樣會給黑客截取系統文件的機會,主機的信息暴露給黑客,無疑是給了對方入侵的機會。
- 增加服務器資源
- 應用層DDoS
應用層 DDoS 攻擊不是發生在網絡層,是發生在 TCP 建立握手成功之后,應用程序處理請求的時候,現在很多常見的 DDoS 攻擊都是應用層攻擊。應用層攻擊千變萬化,目的就是在網絡應用層耗盡你的帶寬,下面列出集中典型的攻擊類型。
CC 攻擊
當時綠盟為了防御 DDoS 攻擊研發了一款叫做 Collapasar
的產品,能夠有效的防御 SYN Flood 攻擊。黑客為了挑釁,研發了一款 Challenge Collapasar
攻擊工具(簡稱 CC)。
CC 攻擊的原理,就是針對消耗資源比較大的頁面不斷發起不正常的請求,導致資源耗盡。因此在發送 CC 攻擊前,我們需要尋找加載比較慢,消耗資源比較多的網頁,比如需要查詢數據庫的頁面、讀寫硬盤文件的等。通過 CC 攻擊,使用爬蟲對某些加載需要消耗大量資源的頁面發起 HTTP 請求。
DNS Flood
DNS Flood 攻擊采用的方法是向被攻擊的服務器發送大量的域名解析請求,通常請求解析的域名是隨機生成或者是網絡世界上根本不存在的域名,被攻擊的DNS 服務器在接收到域名解析請求的時候首先會在服務器上查找是否有對應的緩存,如果查找不到並且該域名無法直接由服務器解析的時候,DNS 服務器會向其上層 DNS 服務器遞歸查詢域名信息。域名解析的過程給服務器帶來了很大的負載,每秒鍾域名解析請求超過一定的數量就會造成 DNS 服務器解析域名超時。
根據微軟的統計數據,一台 DNS 服務器所能承受的動態域名查詢的上限是每秒鍾 9000 個請求。而我們知道,在一台 P3 的 PC 機上可以輕易地構造出每秒鍾幾萬個域名解析請求,足以使一台硬件配置極高的 DNS 服務器癱瘓,由此可見 DNS 服務器的脆弱性。
HTTP 慢速連接攻擊
針對 HTTP 協議,先建立起 HTTP 連接,設置一個較大的 Conetnt-Length,每次只發送很少的字節,讓服務器一直以為 HTTP 頭部沒有傳輸完成,這樣連接一多就很快會出現連接耗盡。
應用層DDoS防御:
-
- 判斷 User-Agent 字段(不可靠,因為可以隨意構造)
- 針對 IP + cookie,限制訪問頻率(由於 cookie 可以更改,IP 可以使用代理,或者肉雞,也不可靠)
- 關閉服務器最大連接數等,合理配置中間件,緩解 DDoS 攻擊。
- 請求中添加驗證碼,比如請求中有數據庫操作的時候。
- 編寫代碼時,盡量實現優化,並合理使用緩存技術,減少數據庫的讀取操作。
- 增加服務器資源