關於Web安全的問題,是一個老生常談的問題,做爲離用戶最近的一層,咱們大前端應該把手伸的更遠一點。javascript
咱們最多見的Web安全攻擊有如下幾種:css
XSS
跨站腳本攻擊CSRF
跨站請求僞造URL
跳轉漏洞ClickJacking
點擊劫持/UI-覆蓋攻擊SQL Injection
SQL注入OS Command Injection
OS命令注入XSS (Cross Site Script),中文是跨站腳本攻擊;其本來縮寫是 CSS,但爲了和層疊樣式表(Cascading Style Sheet)有所區分,於是在安全領域叫作 XSS。html
惡意攻擊者往Web頁面裏插入惡意Script代碼,當用戶瀏覽該頁之時,嵌入其中Web裏面的Script代碼會被執行,從而達到惡意攻擊用戶的目的。前端
XSS攻擊能夠分爲3類:java
Reflected XSS
Stored XSS
DOM-based or local XSS
反射型 XSS 只是簡單地把用戶輸入的數據 「反射」 給瀏覽器,這種攻擊方式每每須要攻擊者誘使用戶點擊一個惡意連接,或者提交一個表單,或者進入一個惡意網站時,注入腳本進入被攻擊者的網站。程序員
僞裝我是一個惡意連接(Click Me~)
web
const http = require('http');
// 啓http服務
const server = http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
res.write('<script>while(true)alert("反射型 XSS 攻擊")</script>');
res.end();
});
server.listen('8000');
複製代碼
這樣就產生了反射型 XSS 攻擊。攻擊者能夠注入任意的惡意腳本進行攻擊,可能注入惡做劇腳本,或者注入能獲取用戶隱私數據(如cookie)的腳本,這取決於攻擊者的目的。正則表達式
存儲型 XSS 會把用戶輸入的數據 "存儲" 在服務器端,當瀏覽器請求數據時,腳本從服務器上傳回並執行。這種 XSS 攻擊具備很強的穩定性。
sql
比較常見的一個場景是攻擊者在社區或論壇上寫下一篇包含惡意 JavaScript 代碼的文章或評論,文章或評論發表後,全部訪問該文章或評論的用戶,都會在他們的瀏覽器中執行這段惡意的 JavaScript 代碼。shell
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>存儲型 XSS</title>
</head>
<body>
<div>Try Me:<input type="text" id="input"></div>
<button id="btn">Submit</button>
<script> const input = document.getElementById('input'); const btn = document.getElementById('btn'); let val; input.addEventListener('change', e => { val = e.target.value; }, false); btn.addEventListener('click', e => { fetch('http://localhost:8000/save', { method: 'POST', body: val }); }, false); </script>
</body>
</html>
複製代碼
const http = require('http');
let userInput = '';
function handleReequest (req, res) {
const method = req.method;
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
if (method === 'POST' && req.url === '/save') {
let body = '';
req.on('data', chunk => {
body += chunk;
});
req.on('end', () => {
if (body) {
userInput = body;
}
res.end();
});
} else {
res.writeHead(200, { 'Content-Type': 'text/html; charset=UTF-8' });
res.write(userInput);
res.end();
}
}
// 啓http服務
const server = http.createServer((req, res)=> {
handleReequest(req, res)
});
server.listen('8000');
複製代碼
基於DOM或本地的XSS實際上是一種特殊類型的反射型XSS,它是基於DOM文檔對象模型的一種漏洞。能夠經過DOM來動態修改頁面內容,從客戶端獲取DOM中的數據並在本地執行。基於這個特性,就能夠利用JS腳原本實現XSS漏洞的利用。
<body>
<input type="text" id="input">
<button id="btn">Submit</button>
<div id="div"></div>
<script> const input = document.getElementById('input'); const btn = document.getElementById('btn'); const div = document.getElementById('div'); let val; input.addEventListener('change', (e) => { val = e.target.value; }, false); btn.addEventListener('click', () => { div.innerHTML = `<a href=${val}>Try Me~</a>` }, false); </script>
</body>
複製代碼
總結: XSS攻擊的本質就是,利用一切手段在目標用戶的瀏覽器中執行攻擊腳本。
防範: 對於一切用戶的輸入、輸出、客戶端的輸出內容視爲不可信,在數據添加到DOM或者執行了DOM API的時候,咱們須要對內容進行HtmlEncode或JavaScriptEncode,以預防XSS攻擊。
如今主流的瀏覽器內置了防範 XSS 的措施,例如 內容安全策略(CSP)。但對於開發者來講,也應該尋找可靠的解決方案來防止 XSS 攻擊。
CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。
一般狀況下,CSRF 攻擊是攻擊者藉助受害者的 Cookie 騙取服務器的信任,能夠在受害者絕不知情的狀況下以受害者名義僞造請求發送給受攻擊服務器,從而在並未受權的狀況下執行在權限保護之下的操做。
關於瀏覽器的Cookie策略請參考HTTP Cookie。
假設有一個BBS站點http://www.a.com
:
當用戶登陸以後,會設置以下 cookie: res.setHeader('Set-Cookie', ['user=william; expires=Fri, 23 Mar 2019 00:00:00 GMT;'])
當登陸後的用戶發起 http://www.a.com/delete?id=666666
請求時,會刪除 id 爲 666666 的帖子。
CSRF攻擊者準備的網站B:<img src="http://www.a.com/delete?id=666666">
當登陸用戶訪問攻擊者的網站B時,會向 www.a.com
發起一個刪除用戶帖子的請求。此時若用戶在切換到 www.a.com
的帖子頁面刷新,會發現ID 爲 666666 的帖子已經被刪除。
要完成一次CSRF攻擊,受害者必須依次完成兩個步驟:
1.驗證 HTTP Referer 字段
2.添加 token 驗證
3.驗證碼
複製代碼
儘管CSRF聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝來自受信任用戶的請求來利用受信任的網站。
與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性,每每同XSS一同做案!
藉助未驗證的URL跳轉,將應用程序引導到不安全的第三方區域,從而致使的安全問題。
當用戶點擊後,通過服務器或者瀏覽器解析後,將會跳到惡意的網站中。
http://a.baidu.com/index?act=go&url=http://evil.cn/
http://b.baidu.com/safecheck.html?id=1&url=http://evil.cn/
http://c.baidu.com/f/user/passport?jumpUrl=http://evil.cn/
複製代碼
經過以GET或者POST的方式接收將要跳轉的URL,而後經過上面的幾種方式的其中一種來跳轉到目標URL。一方面,因爲用戶的輸入會進入Meta,javascript,http頭因此均可能發生相應上下文的漏洞,如xss等等,可是同時,即便只是對於URL跳轉自己功能方面就存在一個缺陷,由於會將用戶瀏覽器從可信的站點導向到不可信的站點,同時若是跳轉的時候帶有敏感數據同樣可能將敏感數據泄漏給不可信的第三方。
① referer的限制
若是肯定傳遞URL參數進入的來源,咱們能夠經過該方式實現安全限制,保證該URL的有效性,避免惡意用戶本身生成跳轉連接
② 加入有效性驗證Token
咱們保證全部生成的連接都是來自於咱們可信域的,經過在生成的連接里加入用戶不可控的Token對生成的連接進行校驗,能夠避免用戶生成本身的惡意連接從而被利用,可是若是功能自己要求比較開放,可能致使有必定的限制。
ClickJacking點擊劫持,也叫UI覆蓋攻擊,攻擊者會利用一個或多個透明或不透明的層來誘騙用戶支持點擊按鈕的操做,而實際的點擊確實用戶看不到的一個按鈕,從而達到在用戶不知情的狀況下實施攻擊。
這種攻擊方式的關鍵在於能夠實現頁中頁的<iframe>
標籤,而且可使用css樣式表將他不可見。
防止點擊劫持有兩種主要方法:
X-FRAME-OPTIONS
X-FRAME-OPTIONS是微軟提出的一個http響應首部,指示瀏覽器不容許從其餘域進行取景,專門用來防護利用iframe嵌套的點擊劫持攻擊。而且在IE八、Firefox3.六、Chrome4以上的版本均能很好的支持。
DENY
: 拒絕任何域加載
SAMEORIGIN
: 容許同源域下加載
ALLOW-FROM
: 能夠定義容許frame加載的頁面地址
頂層判斷
在UI中採用防護性代碼,以確保當前幀是最頂層的窗口,如: top != self || top.location != self.location || top.location != location
圖片覆蓋攻擊(Cross Site Image Overlaying),攻擊者使用一張或多張圖片,利用圖片的style或者可以控制的CSS,將圖片覆蓋在網頁上,造成點擊劫持。固然圖片自己所帶的信息可能就帶有欺騙的含義,這樣不須要用戶點擊,也能達到欺騙的目的。
<a href="http://www.a.com/delete?id=666666">
<img src="~~~" style="~~~" />
</a>
複製代碼
解決方案: 在防護圖片覆蓋攻擊時,須要檢查用戶提交的HTML代碼中,img標籤的style屬性是否可能致使浮出。
SQL 注入漏洞(SQL Injection)是 Web 開發中最多見的一種安全漏洞。能夠用它來從數據庫獲取敏感信息,或者利用數據庫的特性執行添加用戶,導出文件等一系列惡意操做,甚至有可能獲取數據庫乃至系統用戶最高權限。
SQL注入攻擊指的是經過構建特殊的輸入做爲參數傳入Web應用程序,而這些輸入大都是SQL語法裏的一些組合,經過執行SQL語句進而執行攻擊者所要的操做,其主要緣由是程序沒有細緻地過濾用戶輸入的數據,導致非法數據侵入系統。
根據相關技術原理,SQL注入能夠分爲平臺層注入和代碼層注入。前者由不安全的數據庫配置或數據庫平臺的漏洞所致;後者主要是因爲程序員對輸入未進行細緻地過濾,從而執行了非法的數據查詢。基於此,SQL注入的產生緣由一般表如今如下幾方面:
① 不當的類型處理;
② 不安全的數據庫配置;
③ 不合理的查詢集處理;
④ 不當的錯誤處理;
⑤ 轉義字符處理不合適;
⑥ 多個提交處理不當。
當應用程序使用輸入內容來構造動態sql語句以訪問數據庫時,會發生sql注入攻擊。若是代碼使用存儲過程,而這些存儲過程做爲包含未篩選的用戶輸入的字符串來傳遞,也會發生sql注入。sql注入可能致使攻擊者使用應用程序登錄在數據庫中執行命令。相關的SQL注入能夠經過測試工具pangolin進行。
① 永遠不要信任用戶的輸入。對用戶的輸入進行校驗,能夠經過正則表達式,或限制長度;對單引號和雙"-"進行轉換等。
② 永遠不要使用動態拼裝sql,可使用參數化的sql或者直接使用存詢存取。
③ 永遠不要使用管理員權限的數據庫鏈接,爲每一個應用使用單獨的權限有限的數據庫鏈接。
④ 不要把機密信息直接存放,加密或者hash掉密碼和敏感的信息。
⑤ 應用的異常信息應該給出儘量少的提示,最好使用自定義的錯誤信息對原始錯誤信息進行包裝。
⑥ sql注入的檢測方法通常採起輔助軟件或網站平臺來檢測,軟件通常採用sql注入檢測工具jsky,網站平臺就有億思網站安全平臺檢測工具MDCSOFT SCAN等。採用MDCSOFT-IPS能夠有效的防護SQL注入,XSS攻擊等。
OS 注入攻擊是指程序提供了直接執行 Shell 命令的函數的場景,當攻擊者不合理使用,且開發者對用戶參數未考慮安全因素的話,就會執行惡意的命令調用,被攻擊者利用。
OS 命令注入其實原理和 SQL 注入是相似的,只是場景不同而已。 在 Node.js 中可使用 exec()
執行命令經過傳入一段字符串命令,並把一個錯誤或命令處理結果回傳至回調函數中。
let userInput = "user input";
child_process.exec('ls -l ' + userInput, (err, data) => {
console.log(data);
});
複製代碼
攻擊者可使用一個分號";"來結束命令,並開始一個新的調用,他們可使用反引號或$()來運行子命令。還有不少潛在的濫用。
在child_process.exec引擎下,將調用執行"/bin/sh"。而不是目標程序。已發送的命令只是被傳遞給一個新的"/bin/ sh'進程來執行shell。 child_process.exec的名字有必定誤導性 - 這是一個bash的解釋器,而不是啓動一個程序。這意味着,若是直接執行用戶輸入的參數,全部的shell字符可能會產生毀滅性的後果。
在 Node.js 中除了 exec() 以外,還有 execFile() 和 spawn() 兩個方法也能夠用來執行系統命令。它們和 exec() 的區別是後者是直接將一個命令字符串傳給 /bin/sh 執行,而前者是提供了一個數組做爲參數容器,最後參數會被直接傳到 C 的命令執行方法 execve() 中,不容易執行額外的參數。
<!--child_process.execFile -->
let path = "user input";
child_process.execFile('/bin/ls', ['-l', path], (err, result) => {
console.log(result)
});
複製代碼
<!--child_process.spawn-->
let path = "user input";
let ls = child_process.spawn('/bin/ls', ['-l', path])
ls.stdout.on('data', data => {
console.log(data.toString());
});
複製代碼
注意:
使用spawn或execFile並不老是安全的。例如,運行/bin/find,並傳入用戶輸入參數仍有可能致使系統被攻陷。 find命令有一些選項,容許讀/寫任意文件。
參考文章: