第一段引用上面的摘要:
在 go 的 html/template 包中,处理来自不可信来源的 html 内容时,直接使用 html 类型可能会引入安全风险。本文介绍了一种通过解析 html 并仅保留特定允许的标签,从而安全地在 go 模板中渲染部分 html 内容的方法。该方法利用第三方库,例如 go-html-transform,来解析 html,过滤掉未授权的标签和属性,并最终生成安全可信的输出,从而避免潜在的跨站脚本攻击(xss)。
在 Web 应用程序中,尤其是论坛或评论系统,经常需要处理用户提交的 HTML 内容。直接将这些内容未经处理地渲染到页面上,会带来严重的安全风险,例如跨站脚本攻击(XSS)。Go 的 html/template 包提供了强大的 HTML 转义功能,可以有效地防止 XSS 攻击。然而,在某些情况下,我们可能希望允许用户使用一些基本的 HTML 标签,例如 <b>、<i>、<br> 等,来实现简单的格式化。
一种安全的做法是解析 HTML 内容,并仅保留允许的标签和属性。这可以通过以下步骤实现:
-
使用 HTML 解析器: 选择一个合适的 HTML 解析器。go-html-transform 是一个常用的选择,因为它专门设计用于转换和清理 HTML。虽然 Go 1 移除了 exp/html,但 go-html-transform 提供了类似的功能,并且更加健壮。
-
定义白名单: 创建一个白名单,其中包含允许的 HTML 标签和属性。例如,我们可能允许 p、br、b、i 标签,以及 href 属性(仅用于 a 标签)。
立即学习“前端免费学习笔记(深入)”;
-
解析和过滤: 使用 HTML 解析器解析用户提交的 HTML 内容。然后,遍历解析后的 HTML 树,移除所有不在白名单中的标签和属性。
-
生成安全 HTML: 将过滤后的 HTML 树重新序列化为 HTML 字符串。这个字符串可以安全地在模板中渲染,因为它只包含允许的标签和属性。
示例代码 (使用 go-html-transform):
package main import ( "fmt" "strings" "github.com/jaytaylor/html2text" "golang.org/x/net/html" ) // allowedTags 定义允许的 HTML 标签 var allowedTags = map[string]bool{ "p": true, "br": true, "b": true, "i": true, "a": true, } // allowedAttributes 定义允许的 HTML 属性,以及允许的标签 var allowedAttributes = map[string]map[string]bool{ "a": {"href": true}, } // sanitizeHTML 对 HTML 进行清理,只保留白名单中的标签和属性 func sanitizeHTML(htmlString string) (string, error) { root, err := html.Parse(strings.NewReader(htmlString)) if err != nil { return "", err } var f func(*html.node) f = func(n *html.Node) { // 移除不在白名单中的标签 if n.Type == html.ElementNode { if _, ok := allowedTags[n.Data]; !ok { n.Type = html.TextNode n.Data = "" // 移除标签内容 } else { // 清理属性 var attrs []html.Attribute for _, attr := range n.Attr { if allowedAttributes[n.Data] == nil || allowedAttributes[n.Data][attr.Key] { attrs = append(attrs, attr) } } n.Attr = attrs } } // 递归处理子节点 for c := n.FirstChild; c != nil; c = c.NextSibling { f(c) } } f(root) // 将 HTML 树重新序列化为字符串 sanitizedHTML, err := html2text.RenderNode(root) if err != nil { return "", err } return sanitizedHTML, nil } func main() { untrustedHTML := `<p>This is a <b>bold</b> text with a <script>alert("XSS")</script> and <a href="https://example.com">link</a>.</p>` safeHTML, err := sanitizeHTML(untrustedHTML) if err != nil { fmt.Println("Error:", err) return } fmt.Println("Original HTML:", untrustedHTML) fmt.Println("Sanitized HTML:", safeHTML) }
注意事项:
- 性能: HTML 解析和过滤可能比较耗时,尤其是在处理大型 HTML 文档时。考虑使用缓存或其他优化技术来提高性能。
- 复杂性: HTML 解析是一项复杂的任务,需要处理各种边缘情况。确保选择一个成熟、可靠的 HTML 解析器。
- 安全: 仔细审查白名单,确保只允许必要的标签和属性。避免允许可能导致 XSS 攻击的标签和属性,例如 script、onload 等。
- 转义: 即使使用了白名单,仍然建议对输出的 HTML 进行转义,以防止意外的 XSS 攻击。Go 的 html/template 包会自动进行转义。
总结:
通过解析 HTML 并仅保留白名单中的标签和属性,可以安全地在 Go 模板中渲染部分 HTML 内容。这种方法可以有效地防止 XSS 攻击,同时允许用户使用一些基本的 HTML 格式化。请务必谨慎选择 HTML 解析器,并仔细审查白名单,以确保应用程序的安全性。 使用 go-html-transform 库能够方便地实现 HTML 的解析和清理,并提供更安全的 HTML 输出。
评论(已关闭)
评论已关闭