跨站點指令碼(XSS)

問題

跨站點指令碼是 Web 客戶端意外執行遠端程式碼。如果任何 Web 應用程式從使用者獲取輸入並直接在網頁上輸出,則可能會將自身暴露給 XSS。如果輸入包括 HTML 或 JavaScript,則當 Web 客戶端呈現此內容時,可以執行遠端程式碼。

例如,如果第三方包含 JavaScript 檔案:

// http://example.com/runme.js
document.write("I'm running");

PHP 應用程式直接輸出傳遞給它的字串:

<?php
echo '<div>' . $_GET['input'] . '</div>';

如果未經檢查的 GET 引數包含 <script src="http://example.com/runme.js"></script>,則 PHP 指令碼的輸出將為:

<div><script src="http://example.com/runme.js"></script></div>

第三方 JavaScript 將執行,使用者將在網頁上看到我正在執行

作為一般規則,永遠不要相信來自客戶的輸入。每個 GET,POST 和 cookie 值都可以是任何值,因此應該進行驗證。輸出任何這些值時,請將它們轉義,以便不會以意外方式對它們進行求值。

請記住,即使在最簡單的應用程式中,資料也可以移動,並且很難跟蹤所有來源。因此,始終轉義輸出是最佳做法。

PHP 根據上下文提供了一些轉義輸出的方法。

過濾功能

PHPs 過濾器函式允許以多種方式對 PHP 指令碼的輸入資料進行清理驗證 。它們在儲存或輸出客戶端輸入時很有用。

HTML 編碼

htmlspecialchars 會將任何“HTML 特殊字元”轉換為 HTML 編碼,這意味著它們不會被處理為標準 HTML。要使用此方法修復上一個示例:

<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';

輸出:

<div>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

<div> 標記內的所有內容都不會被瀏覽器解釋為 JavaScript 標記,而是作為簡單的文字節點。使用者將安全地看到:

<script src="http://example.com/runme.js"></script>

網址編碼

當輸出動態生成的 URL 時,PHP 提供 urlencode 函式以安全地輸出有效的 URL。因此,例如,如果使用者能夠輸入成為另一個 GET 引數的一部分的資料:

<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';

任何惡意輸入都將轉換為編碼的 URL 引數。

使用專門的外部庫或 OWASP AntiSamy 列表

有時你會想要傳送 HTML 或其他型別的程式碼輸入。你需要維護授權單詞列表(白名單)和未授權單詞(黑名單)。

你可以在 OWASP AntiSamy 網站下載標準列表。每個列表適合特定型別的互動(ebay api,tinyMCE 等…)。它是開源的。

現有的庫可以過濾 HTML 並防止針對一般情況的 XSS 攻擊,並且至少與 AntiSamy 列表一樣易於使用。例如,你有 HTML Purifier