{!! $var !!} 直接輸出未轉義 HTML,極高風險。{{ $var }} 雖自動 htmlspecialchars,但無法處理「允許部分 HTML 標籤(如 <b>、<a>)」的富文本需求。<script>、onerror、style="expression(...)" 等攻擊向量。composer require mews/purifier
// config/app.php (若未自動發現)
'providers' => [
Mews\Purifier\PurifierServiceProvider::class,
],
'aliases' => [
'Purifier' => Mews\Purifier\Facades\Purifier::class,
]
php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"
產生 config/purifier.php,可自訂白名單:
return [
'encoding' => 'UTF-8',
'finalize' => true,
'cachePath' => storage_path('app/purifier'),
'settings' => [
'default' => [
'HTML.Doctype' => 'HTML5',
'HTML.Allowed' => 'div,b,strong,i,em,u,strike,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src],table,thead,tbody,tr,th,td',
'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,color,background-color,text-align',
'AutoFormat.AutoParagraph' => true,
'AutoFormat.RemoveEmpty' => true,
],
'custom' => [
'Attr.EnableID' => true,
],
'youtube' => [
'HTML.SafeIframe' => true,
'URI.SafeIframeRegexp' => '%^(https?:)?//(www\.youtube\.com/embed/|player\.vimeo\.com/video/)%',
],
],
];
clean()(全域可用)$safeHtml = clean($request->input('content')); // 使用 default 設定
$safeHtml = clean($request->input('content'), 'youtube'); // 使用 youtube 設定
$safeHtml = clean($request->input('content'), ['HTML.Allowed' => 'p,b,a[href]']); // 臨時覆蓋
use Mews\Purifier\Facades\Purifier;
$safeHtml = Purifier::clean($request->input('content'));
$safeHtml = Purifier::clean($request->input('content'), 'custom');
// App\Models\Article.php
public function setContentAttribute($value)
{
$this->attributes['content'] = clean($value);
}
// 讀取時若需原始內容,另設 raw_content 欄位或關閉存取器
function cleanXss(&$string, bool $low = false): bool
{
if (!is_array($string)) {
$string = trim($string);
$string = strip_tags($string); // 移除所有標籤(嚴格模式)
$string = htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
if ($low) return true;
// 進一步過濾危險字元
$string = str_replace(['"', "\\", "'", "/", "..", "../", "./", "//"], '', $string);
$string = preg_replace('/%0[0-8bcef]/', '', $string);
$string = preg_replace('/%1[0-9a-f]/', '', $string);
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $string);
return true;
}
foreach (array_keys($string) as $key) {
cleanXss($string[$key]);
}
return true;
}
⚠️ strip_tags 會移除所有標籤,無法保留安全富文本。生產環境強烈建議用 HTMLPurifier。
clean() 淨化。{{ }} 自動轉義、!! 僅用於經 clean() 的內容。Content-Security-Policy 限制腳本來源、X-Content-Type-Options: nosniff。HttpOnly、Secure、SameSite=Lax。Laravel 專案防 XSS 標準配置:composer require mews/purifier → 發布配置 → 統一用 clean() 或模型存取器淨化富文本 → Blade 輸出用 {{ }} → 配置 CSP 標頭。零成本、高效能、符合合規要求。