PHP中HTML標(biāo)簽過濾的5種有效方法
什么是XSS攻擊?
XSS(Cross-Site Scripting)攻擊是指攻擊者在網(wǎng)頁中插入惡意腳本,當(dāng)其他用戶瀏覽該頁面時(shí),惡意腳本會(huì)被執(zhí)行,從而盜取用戶信息、會(huì)話令牌或進(jìn)行其他惡意操作。
方法一:htmlspecialchars() - 最常用的轉(zhuǎn)義方法
htmlspecialchars() 是PHP中最基本的XSS防護(hù)函數(shù),它將特殊字符轉(zhuǎn)換為HTML實(shí)體:
<?php
$input = '<script>alert("XSS攻擊")</script><p>正常內(nèi)容</p>';
$safe_output = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
echo $safe_output;
// 輸出:<script>alert("XSS攻擊")</script><p>正常內(nèi)容</p>
參數(shù)詳解:
ENT_QUOTES:轉(zhuǎn)換雙引號(hào)和單引號(hào)UTF-8:指定字符編碼,防止編碼繞過攻擊
適用場(chǎng)景: 純文本輸出,不需要保留任何HTML格式
方法二:strip_tags() - 徹底移除HTML標(biāo)簽
如果你確定不需要任何HTML標(biāo)簽,使用strip_tags()可以徹底移除它們:
<?php
$input = '<script>alert("XSS")</script><p>正文內(nèi)容</p><b>加粗文本</b>';
$safe_output = strip_tags($input);
echo $safe_output;
// 輸出:alert("XSS")正文內(nèi)容加粗文本
選擇性保留標(biāo)簽:
<?php
$input = '<script>alert("XSS")</script><p>正文</p><b>加粗</b><i>斜體</i>';
$safe_output = strip_tags($input, '<p><b>'); // 只保留<p>和<b>標(biāo)簽
echo $safe_output;
// 輸出:<p>正文</p><b>加粗</b>斜體
- 優(yōu)點(diǎn): 簡單直接,性能好
- 缺點(diǎn): 無法過濾標(biāo)簽內(nèi)的屬性
方法三:filter_var() - 使用PHP過濾器擴(kuò)展
PHP過濾器擴(kuò)展提供了更規(guī)范的過濾方式:
<?php
$input = '<script>alert("XSS")</script><p>正常內(nèi)容</p>';
$safe_output = filter_var($input, FILTER_SANITIZE_STRING);
echo $safe_output;
// 輸出:alert("XSS")正常內(nèi)容
// 專門用于過濾HTML
$html_output = filter_var($input, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
方法四:HTMLPurifier - 企業(yè)級(jí)解決方案
對(duì)于需要保留安全HTML內(nèi)容的場(chǎng)景,HTMLPurifier是最佳選擇:
安裝方法:
composer require ezyang/htmlpurifier
使用示例:
<?php
require_once 'vendor/autoload.php';
$config = HTMLPurifier_Config::createDefault();
// 自定義配置
$config->set('HTML.Allowed', 'p,br,strong,em,ul,ol,li,a[href]');
$config->set('AutoFormat.RemoveEmpty', true);
$purifier = new HTMLPurifier($config);
$input = '<script>alert("XSS")</script><p class="test">安全內(nèi)容</p><a rel="external nofollow" rel="external nofollow" >鏈接</a>';
$safe_output = $purifier->purify($input);
echo $safe_output;
// 輸出:<p>安全內(nèi)容</p><a rel="external nofollow" rel="external nofollow" >鏈接</a>
優(yōu)勢(shì):
- 遵循HTML標(biāo)準(zhǔn)
- 支持細(xì)粒度配置
- 能過濾危險(xiǎn)的標(biāo)簽屬性
- 社區(qū)活躍,持續(xù)更新
方法五:自定義過濾函數(shù)
針對(duì)特定需求,可以創(chuàng)建自定義過濾函數(shù):
<?php
function advanced_xss_clean($data) {
if (empty($data)) return '';
// 遞歸處理數(shù)組
if (is_array($data)) {
return array_map('advanced_xss_clean', $data);
}
// 移除NULL字節(jié)
$data = str_replace(chr(0), '', $data);
// 轉(zhuǎn)換特殊字符
$data = htmlspecialchars($data, ENT_QUOTES | ENT_HTML5, 'UTF-8', true);
// 移除危險(xiǎn)的JavaScript模式
$patterns = [
'/javascript:/i',
'/vbscript:/i',
'/on\w+\s*=/i', // 移除onclick等事件屬性
'/expression\s*\(/i' // 移除CSS表達(dá)式
];
foreach ($patterns as $pattern) {
$data = preg_replace($pattern, '', $data);
}
return $data;
}
// 使用示例
$input = '<img src="javascript:alert(1)" onclick="malicious()">';
echo advanced_xss_clean($input);
?>
實(shí)戰(zhàn):根據(jù)不同場(chǎng)景選擇防護(hù)策略
場(chǎng)景1:用戶評(píng)論(允許有限HTML)
<?php
function filter_comment($content) {
$allowed_tags = '<p><br><strong><em><ul><ol><li><a>';
$content = strip_tags($content, $allowed_tags);
// 進(jìn)一步使用HTMLPurifier進(jìn)行嚴(yán)格過濾
require_once 'HTMLPurifier.auto.php';
$purifier = new HTMLPurifier();
return $purifier->purify($content);
}
?>
場(chǎng)景2:顯示用戶名(純文本)
<?php
function filter_username($username) {
return htmlspecialchars(trim($username), ENT_QUOTES, 'UTF-8');
}
?>
場(chǎng)景3:URL參數(shù)
<?php
function filter_url($url) {
$url = filter_var($url, FILTER_SANITIZE_URL);
if (filter_var($url, FILTER_VALIDATE_URL)) {
return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
}
return '';
}
?>
完整的安全防護(hù)示例
<?php
class SecurityHelper {
public static function xss_clean($data, $context = 'text') {
if (empty($data)) return $data;
if (is_array($data)) {
return array_map([self::class, 'xss_clean'], $data);
}
switch ($context) {
case 'html':
// 使用HTMLPurifier處理富文本
return self::purify_html($data);
case 'attribute':
// 用于HTML屬性
return self::escape_attribute($data);
case 'text':
default:
// 純文本轉(zhuǎn)義
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
}
private static function purify_html($html) {
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,br,strong,em,ul,ol,li,a[href|title]');
$purifier = new HTMLPurifier($config);
return $purifier->purify($html);
}
private static function escape_attribute($data) {
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8', false);
}
}
// 使用示例
$user_input = [
'username' => '<script>alert("xss")</script>',
'comment' => '<p>正常評(píng)論</p><script>惡意代碼</script>',
'website' => 'javascript:alert(1)'
];
$cleaned_data = SecurityHelper::xss_clean($user_input);
print_r($cleaned_data);
?>
防御深度建議
- 輸入驗(yàn)證:在接收數(shù)據(jù)時(shí)進(jìn)行嚴(yán)格驗(yàn)證
- 輸出轉(zhuǎn)義:根據(jù)輸出上下文進(jìn)行適當(dāng)?shù)霓D(zhuǎn)義
- 內(nèi)容安全策略(CSP):設(shè)置HTTP頭
header("Content-Security-Policy: default-src 'self'");- HttpOnly Cookie:防止Cookie被JavaScript讀取
- 框架安全特性:優(yōu)先使用框架提供的安全方法
總結(jié)
XSS防護(hù)是一個(gè)多層次的過程,需要根據(jù)具體場(chǎng)景選擇合適的過濾策略:
- 純文本輸出:使用
htmlspecialchars() - 完全移除HTML:使用
strip_tags() - 保留安全HTML:使用 HTMLPurifier
- 企業(yè)級(jí)應(yīng)用:結(jié)合多種方法,建立完整防護(hù)體系
記?。?strong>永遠(yuǎn)不要信任用戶輸入,在顯示任何用戶提供的數(shù)據(jù)之前,都要進(jìn)行適當(dāng)?shù)倪^濾和轉(zhuǎn)義。
到此這篇關(guān)于PHP中HTML標(biāo)簽過濾的5種有效方法的文章就介紹到這了,更多相關(guān)PHP HTML標(biāo)簽過濾內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PHP后期靜態(tài)綁定之self::限制實(shí)例分析
這篇文章主要介紹了PHP后期靜態(tài)綁定之self::限制,結(jié)合實(shí)例形式分析了php后期靜態(tài)綁定self::與static相關(guān)使用技巧,需要的朋友可以參考下2018-12-12
PHP static局部靜態(tài)變量和全局靜態(tài)變量總結(jié)
使用靜態(tài)局部變量的原因是它不能被外部使用,但是它的值依然在沒此使用后保留。雖然使用全局變量可以實(shí)現(xiàn)相同的功能,但是它經(jīng)常會(huì)造成意外2014-03-03
PHP實(shí)現(xiàn)的DES加密解密封裝類完整實(shí)例
這篇文章主要介紹了PHP實(shí)現(xiàn)的DES加密解密封裝類,結(jié)合完整實(shí)例形式分析了php DES加密解密封裝類的定義與使用技巧,需要的朋友可以參考下2017-04-04

