# 漏洞总结 ## 漏洞概述 该漏洞为 **存储型 XSS(Stored Cross-Site Scripting)**,发生在 `page/article` 内容中。攻击者可以通过在文章内容或页面内容中注入恶意 HTML/JavaScript 代码,当其他用户查看这些内容时,恶意脚本将在其浏览器中执行,可能导致用户会话被劫持、敏感信息泄露等安全问题。 ## 影响范围 - **受影响组件**:`BraveCMS-2.0` 系统中的文章(Article)和页面(Page)内容存储与展示功能。 - **受影响文件**: - `app/Http/Controllers/Dashboard/ArticleController.php` - `app/Http/Controllers/Dashboard/PageController.php` - `app/Http/Controllers/ContactController.php` - `app/Support/HtmlSanitizer.php` - 相关 Blade 模板文件(如 `contact-message.blade.php`, `page.blade.php`, `single.blade.php`) ## 修复方案 1. **引入 HTML 净化机制**:新增 `app/Support/HtmlSanitizer.php` 类,用于对输入内容进行 HTML 标签和属性的过滤与净化。 2. **控制器层集成净化逻辑**: - 在 `ArticleController` 的 `save()` 和 `update()` 方法中,对 `content` 字段调用 `HtmlSanitizer::clean()` 进行净化。 - 在 `PageController` 的 `save()` 和 `update()` 方法中,同样对 `content` 字段进行净化。 3. **表单验证增强**:在 `ContactController` 中增加对 `name`, `email`, `phone` 等字段的严格验证,防止恶意输入。 4. **模板层安全输出**:在 Blade 模板中使用 `{{ }}` 语法自动转义输出内容,避免直接渲染未过滤的 HTML。 ## POC / 利用代码(来自修复补丁) ### 新增 HTML 净化器类 `app/Support/HtmlSanitizer.php` ```php ['href', 'title'], 'img' => ['src', 'alt', 'title'] ]; public static function clean($html) { if (!trim($html) || trim($html) === '') return $html; libxml_use_internal_errors(true); $dom = new DOMDocument('1.0', 'UTF-8'); $dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $nodes = $dom->getElementsByTagName('*'); for ($i = $nodes->length - 1; $i >= 0; $i--) { $node = $nodes->item($i); if (!($node instanceof DOMElement)) continue; $tag = strtolower($node->nodeName); if (!in_array($tag, self::$allowedTags, true)) { if ($node->parentNode) $node->parentNode->removeChild($node); continue; } self::cleanAttributes($node, $tag); } foreach (iterator_to_array($dom->childNodes) as $child) { if ($child->nodeType === XML_PI_NODE || $child->nodeType === XML_COMMENT_NODE) { $dom->removeChild($child); } } return $dom->saveHTML(); } private static function cleanAttributes($node, $tag) { if (!$node->hasAttributes()) return; $allowed = isset(self::$allowedAttributes[$tag]) ? self::$allowedAttributes[$tag] : []; $remove = []; foreach ($node->attributes as $attr) { $name = strtolower($attr->nodeName); $value = $attr->nodeValue; if (!in_array($name, $allowed, true)) { $remove[] = $name; continue; } if ($name === 'href' || $name === 'src') { if (!self::isSafeUrl($value)) { $remove[] = $name; } } foreach ($remove as $a) $node->removeAttribute($a); } } private static function isSafeUrl($url) { $url = html_entity_decode($url, ENT_QUOTES | ENT_HTML5); $url = strtolower(trim(preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $url))); if ($url === '') return false; return !( strpos($url, 'javascript:') === 0 || strpos($url, 'vbscript:') === 0 || strpos($url, 'data:') === 0 || strpos($url, 'file:') === 0 || strpos($url, 'about:') === 0 ); } } ``` ### 控制器修改示例(`ArticleController.php`) ```php // 在 save 方法中 'content' => \App\Support\HtmlSanitizer::clean($request->get('content')), // 在 update 方法中 $article->content = \App\Support\HtmlSanitizer::clean($request->get('content')); ``` ### 控制器修改示例(`PageController.php`) ```php // 在 save 方法中 'content' => \App\Support\HtmlSanitizer::clean($request->get('content')), // 在 update 方法中 $page->content = \App\Support\HtmlSanitizer::clean($request->get('content')); ``` ### 控制器修改示例(`ContactController.php`) ```php // 增加表单验证规则 $rules = [ 'name' => 'required', 'email' => 'required|email', 'phone' => 'required', 'msg' => 'nullable', ]; // 增加错误提示 ->with('error', 'There are invalid fields in the form.'); ``` ### 模板修改示例(`page.blade.php`) ```html {{ $page->content }} ``` ### 模板修改示例(`single.blade.php`) ```html {{ $page->content }} ``` ### 模板修改示例(`contact-message.blade.php`) ```html {{ $msg }} ``` --- > **注意**:以上代码为修复补丁中的关键部分,实际部署时需确保所有用户输入均经过净化处理,并启用 CSRF 保护、XSS 防护头等安全机制。