首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHPCMS 問答模組存儲型 XSS 漏洞分析:黑名單過濾失效、HTML5 攻擊向量與修復方案

     編輯:PHP 相關知識

PHPCMS 問答模組編輯器開放原始碼編輯功能,導致存儲型 XSS。本文複現漏洞成因,分析黑名單過濾繞過技術 (HTML5 新標籤/屬性/事件)、構建無需用戶交互的自動觸發 Payload,並給出白名單過濾、CSP、編輯器配置等多層次修復方案。

一、漏洞背景與影響

  • 組件:PHPCMS 問答模組回覆編輯器
  • 觸發點:編輯器「原始碼模式」提交內容
  • 漏洞類型:存儲型 XSS (Stored XSS)
  • 影響範圍:所有瀏覽受感染頁面的用戶 (含管理員)
  • 風險等級:高 (可竊取 Cookie、劫持會話、鍵盤記錄、內網探測、惡意下載)

二、漏洞複現與繞過過程

1. 初始測試:常規 Payload 被攔截

<script>alert(1)</script>
<img src=x onerror=alert(1)>

結果:均被後端過濾器移除/轉義,無法執行。

2. 繞過策略:利用 HTML5 非標準/新增特性

參考 HTML5 Security Cheatsheet,測試多種繞過向量:

Payload觸發條件瀏覽器支援結果
<form id="test"></form><button form="test" formaction="javascript:alert(1)">X</button>需用戶點擊按鈕現代瀏覽器✅ 繞過 (未過濾 formaction)
<input onfocus=alert(1) autofocus>頁面載入自動聚焦觸發IE10+, Chrome, Firefox 4.5+✅ 繞過 (未過濾 onfocus/autofocus)
<video><source onerror="alert(1)"></video>載入失敗觸發支援 video 的瀏覽器❌ 被過濾
<details open ontoggle=alert(1)>展開/折疊觸發Chrome, Firefox, Edge❌ 被過濾
<svg onload=alert(1)>SVG 載入觸發現代瀏覽器❌ 被過濾

3. 關鍵突破:<input onfocus=... autofocus> 無需交互自動觸發

<input onfocus=alert(1) autofocus>

頁面載入時,瀏覽器自動聚焦該輸入框 → 觸發 onfocus → 執行 JS。無需用戶點擊,隱蔽性極強。

4. 武器化:結合 eval() 執行任意代碼

<input onfocus=eval(atob("YWxlcnQoZG9jdW1lbnQuY29va2llKQ==")) autofocus>

進階:構造鍵盤記錄、表單劫持、BeEF 掛馬、內網掃描等完整攻擊鏈。

三、根因分析:黑名單過濾的本質缺陷

1. 黑名單機制典型實現 (PHPCMS 類似)

<?php
// 簡化版黑名單過濾邏輯
function htmlFilter($html) {
    $blacklist = [
        '/<script/i', '/on\w+\s*=/i', '/javascript:/i', '/vbscript:/i',
        '/<iframe/i', '/<object/i', '/<embed/i', '/<applet/i',
        '/expression\s*\(/i', '/url\s*\(/i', '/@import/i'
    ];
    foreach ($blacklist as $pattern) {
        $html = preg_replace($pattern, '', $html);
    }
    return $html;
}
?>

2. 為什麼黑名單必然失效?

  1. HTML 標準持續演進:HTML5 新增大量標籤 (video, audio, canvas, svg, details, dialog, slot, template)、屬性 (formaction, autofocus, onfocus, ontoggle, onscroll)、事件,黑名單永遠追不上
  2. 瀏覽器解析容錯極強:標籤嵌套錯誤、屬性無引號、大小寫混合、實體編碼、Unicode 正規化、Null 字節注入,均可繞過正則
  3. 編碼繞過:URL 編碼、Unicode 編碼、HTML 實體編碼、雙重編碼、UTF-7/UTF-32 等
  4. 上下文敏感:同樣字串在 HTML 屬性、JS 字串、CSS、URL、HTML 註釋中語義完全不同,單一正則無法覆蓋所有上下文

四、修復方案:多層次纵深防禦

方案一:白名單過濾 (核心修復,強制推薦)

<?php
/**
 * 基於 HTMLPurifier 的白名單過濾 (業界標準)
 * composer require ezyang/htmlpurifier
 */
require_once 'vendor/autoload.php';

function purifyHtml(string $dirtyHtml): string
{
    $config = HTMLPurifier_Config::createDefault();
    
    // 1. 定義允許的標籤與屬性 (極小集合)
    $config->set('HTML.AllowedElements', [
        'p', 'br', 'strong', 'em', 'u', 's', 'span', 'div',
        'ul', 'ol', 'li', 'blockquote', 'pre', 'code',
        'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
        'a', 'img', 'table', 'thead', 'tbody', 'tr', 'th', 'td',
    ]);
    $config->set('HTML.AllowedAttributes', [
        'a.href', 'a.title', 'a.target', 'a.rel',
        'img.src', 'img.alt', 'img.width', 'img.height', 'img.title',
        'span.style', 'div.style', 'p.style', 'td.style', 'th.style',
        'td.colspan', 'td.rowspan', 'th.colspan', 'th.rowspan',
    ]);
    
    // 2. 強制安全屬性
    $config->set('Attr.EnableID', true);
    $config->set('HTML.TargetBlank', '_blank'); // 強制 target=_blank 加 rel=noopener
    $config->set('HTML.SafeIframe', false);     // 禁用 iframe
    $config->set('HTML.SafeObject', false);     // 禁用 object/embed
    $config->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true]);
    $config->set('URI.DisableExternalResources', true); // 禁用外部圖片/資源 (可選)
    
    // 3. CSS 白名單 (防 CSS XSS)
    $config->set('CSS.AllowedProperties', [
        'color', 'background-color', 'font-size', 'font-weight', 'font-family',
        'text-align', 'text-decoration', 'margin', 'padding', 'border',
        'width', 'height', 'max-width', 'max-height',
    ]);
    
    $purifier = new HTMLPurifier($config);
    return $purifier->purify($dirtyHtml);
}

// 使用
$safeHtml = purifyHtml($_POST['content']);
?>

方案二:編輯器層面限制 (輔助)

  • 移除「原始碼/HTML 源碼」按鈕:普通用戶無需直接編輯 HTML
  • 配置 CKEditor/UEditor/TinyMCE 白名單:
    // CKEditor 5 配置
    config.htmlSupport = {
        allow: [
            { name: 'p', attributes: { class: true } },
            { name: 'strong', attributes: {} },
            { name: 'a', attributes: { href: true, target: true, rel: true } },
            // ... 僅允許必要標籤/屬性
        ]
    };
  • 啟用編輯器內建 XSS 過濾:config.htmlEmbed、config.pasteFilter

方案三:輸出端編碼 (最後一道防線)

<?php
// 模板引擎自動逃逸 (Blade, Twig, Smarty, Latte 等默認開啟)
// 原生 PHP 輸出
echo htmlspecialchars($userContent, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

// 若必須輸出「安全 HTML」(經白名單過濾後)
echo $purifiedHtml; // 不再逃逸,但已由 Purifier 保證安全
?>

方案四:內容安全策略 (CSP) 纵深防禦

# Apache / Nginx / PHP header()
Header always set Content-Security-Policy "
    default-src 'self';
    script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic' https://cdn.example.com;
    style-src 'self' 'nonce-{RANDOM}' https://fonts.googleapis.com;
    img-src 'self' data: https:;
    font-src 'self' https://fonts.gstatic.com;
    connect-src 'self' https://api.example.com;
    frame-ancestors 'none';
    base-uri 'self';
    form-action 'self';
    object-src 'none';
    base-uri 'self';
"
# 關鍵:'strict-dynamic' + nonce 配合,繞過舊版瀏覽器限制
# 現代框架 (Laravel, Symfony) 內建 CSP nonce 支援

方案五:Cookie 安全屬性 (減輕危害)

<?php
// 設置 Session Cookie
ini_set('session.cookie_httponly', 1);    // JS 不可讀
ini_set('session.cookie_secure', 1);      // 僅 HTTPS
ini_set('session.cookie_samesite', 'Strict'); // 防 CSRF
session_start();

// 關鍵業務 Cookie
setcookie('auth_token', $token, [
    'httponly' => true,
    'secure' => true,
    'samesite' => 'Strict',
    'path' => '/',
    'domain' => '.example.com',
]);
?>

五、反射型 XSS 附帶修復

文中提及:https://host/index.php?m=ask&c=team&a=team_list&order=team_point&catid=&belong=team&name="><script>alert(1)</script>

修復:控制器輸出前統一 htmlspecialchars、模板引擎自動逃逸、路由參數驗證 (白名單/正則)。

六、修復驗證清單

  • [ ] 後端集成 HTMLPurifier 白名單過濾,單元測試覆蓋 html5sec.org 所有 Payload
  • [ ] 編輯器移除源碼模式/配置標籤白名單
  • [ ] 模板引擎自動逃逸生效,無原始 echo $var
  • [ ] CSP 標頭部署並通過 CSP Evaluator 評分
  • [ ] Cookie 設置 HttpOnly、Secure、SameSite=Strict
  • [ ] 反射型 XSS 參數驗證與輸出編碼
  • [ ] 部署 WAF (ModSecurity/Cloudflare) 規則集 (OWASP CRS) 作為邊界攔截
  • [ ] 定期掃描:XSS 掃描器 (OWASP ZAP, Burp Suite, XSStrike) + 人工滲透測試

七、總結

  1. 黑名單過濾 XSS 是不可能完成的任務:HTML 標準演進、瀏覽器解析複雜性、編碼繞過、上下文敏感,註定失效
  2. 白名單過濾 (HTMLPurifier) 是唯一可靠的服務端方案:定義允許集合,拒絕其餘一切
  3. 纵深防禦體系:編輯器限制 → 服務端白名單 → 輸出編碼 → CSP → Cookie 屬性 → WAF → 定期測試
  4. 老系統改造優先級:先接入 HTMLPurifier 存量數據清洗,再推進 CSP、編輯器升級、框架遷移

安全不是功能,是過程。將 XSS 防禦納入 SDLC 每個環節,才能從根本上消除此類漏洞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved