跨站點指令碼(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><script src="http://example.com/runme.js"></script></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