在任何 wbe 應(yīng)用中展示用戶輸出時(shí),首先對(duì)其進(jìn)行“凈化”去除任何潛在危險(xiǎn)的 HTML 是非常必要的。 一個(gè)惡意的用戶可以制作某些 HTML,若被你的 web 應(yīng)用直接輸出,對(duì)查看它的人來(lái)說(shuō)會(huì)很危險(xiǎn)。
雖然可以嘗試使用正則表達(dá)式來(lái)凈化 HTML,但不要這樣做。HTML是一種復(fù)雜的語(yǔ)言,試圖使用正則表達(dá)式來(lái)凈化 HTML 幾乎總是失敗的。
你可能會(huì)找到建議你使用 strip_tags() 函數(shù)的觀點(diǎn)。 雖然 strip_tags() 從技術(shù)上來(lái)說(shuō)是安全的,但如果輸入的不合法的 HTML(比如, 沒(méi)有結(jié)束標(biāo)簽),它就成了一個(gè)「愚蠢」的函數(shù),可能會(huì)去除比你期望的更多的內(nèi)容。 由于非技術(shù)用戶在通信中經(jīng)常使用 < 和 > 字符,strip_tags() 也就不是一個(gè)好的選擇了。
如果閱讀了驗(yàn)證郵件地址一節(jié), 你也許也會(huì)考慮使用 filter_var() 函數(shù)。 然而 filter_var() 函數(shù)在遇到斷行時(shí)會(huì)出現(xiàn)問(wèn)題, 并且需要不直觀的配置以接近 htmlentities() 函數(shù)的效果, 因此也不是一個(gè)好的選擇。
如果你的 web 應(yīng)用僅需要完全地轉(zhuǎn)義(因此可以無(wú)害地呈現(xiàn),但不是完全去除) HTML, 則使用 PHP 的內(nèi)建 htmlentities() 函數(shù)。 這個(gè)函數(shù)要比 HTML Purifier 快得多,因此它不對(duì) HTML 做任何驗(yàn)證---僅轉(zhuǎn)義所有東西。
htmlentities() 不同于類(lèi)似功能的函數(shù)htmlspecialchars(), 它會(huì)編碼所有適用的 HTML 實(shí)體,而不僅僅是一個(gè)小的子集。
<?php
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Twiddling my evil mustache...</div>';
// Use the ENT_QUOTES flag to make sure both single and double quotes are escaped.
// Use the UTF-8 character encoding if you've stored the text as UTF-8 (as you should have).
// See the UTF-8 section in this document for more details.
$safeHtml = htmlentities($evilHtml, ENT_QUOTES, 'UTF-8');
// $safeHtml is now fully escaped HTML. You can output $safeHtml to your users without fear!
?>
對(duì)于很多 web 應(yīng)用來(lái)說(shuō),簡(jiǎn)單地轉(zhuǎn)義 HTML 是不夠的。 你可能想完全去除任何HTML,或者允許一小部分子集的 HTML 存在。 若是如此,則使用 HTML Purifier 庫(kù)。
HTML Purifier 是一個(gè)經(jīng)過(guò)充分測(cè)試但效率比較低的庫(kù)。 這就是為什么如果你的需求并不復(fù)雜就應(yīng)使用 htmlentities(), 因?yàn)樗男室斓枚唷?/p>
HTML Purifier 相比 strip_tags() 是有優(yōu)勢(shì)的, 因?yàn)樗趦艋?HTML 之前會(huì)對(duì)其校驗(yàn)。 這意味著如果用戶輸入無(wú)效 HTML,HTML Purifier 相比 strip_tags() 更能保留 HTML 的原意。 HTML Purifier 高度可定制,允許你為 HTML 的一個(gè)子集建立白名單來(lái)允許這個(gè) HTML 子集的實(shí)體存在輸出中。
但其缺點(diǎn)就是相當(dāng)?shù)穆?,它要求一些設(shè)置,在一個(gè)共享主機(jī)的環(huán)境里可能是不可行的。 其文檔通常也復(fù)雜而不易理解。 以下示例是一個(gè)基本的使用配置。 查看文檔閱讀 HTML Purifier 提供的更多更高級(jí)的特性。
<?php
// Include the HTML Purifier library
require_once('htmlpurifier-4.4.0/HTMLPurifier.auto.php');
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Twiddling my evil mustache...</div>';
// Set up the HTML Purifier object with the default configuration.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
$safeHtml = $purifier->purify($evilHtml);
// $safeHtml is now sanitized. You can output $safeHtml to your users without fear!
?>
以錯(cuò)誤的字符編碼使用 htmlentities() 會(huì)造成意想不到的輸出。 在調(diào)用該函數(shù)時(shí)始終確認(rèn)指定了一種字符編碼,并且該編碼與將被凈化的字符串的編碼相匹配。 更多細(xì)節(jié)請(qǐng)查看 UTF-8 一節(jié)。
使用 htmlentities() 時(shí),始終包含 ENT_QUOTES 和字符編碼參數(shù)。 默認(rèn)情況下,htmlentities() 不會(huì)對(duì)單引號(hào)編碼。多愚蠢的默認(rèn)做法!