• Golang html/template包实现跳过HTML转义


    使用golang标准库中的html/template时,在默认情况下渲染模版时为了安全等原因,会将字符串中的部分符号进行转义。例如在下面的例子中,我们定义了一个简单的HTML模版:

    <body>
      <main>
        {{.Content}}
      </main>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们直接使用默认设置,并传入带有HTML标签的文本进行渲染:

    // content内容为上面的模版
    // var content string
    tpl, err := template.New("example").Parse(content)
    if err != nil {
      // ...
    }
    buf := new(bytes.Buffer)
    tpl.Execute(buf, map[string]string{
      "Content": "<p>Hello, world!</p>",
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这样的情况下,上述内容将被转义并最终得到下面的文本,而非期望中嵌入带有HTML标签的文本:

    <body>
      <main>
        &lt;p&gt;Hello World&lt;/p&gt;
      </main>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    传递template.HTML类型值避免转义

    为了实现避免转义的效果,可以在执行Execute()方法前,将带有HTML标签的文本转为template.HTML类型:

    tpl.Execute(buf, map[string]any{
      "Content": template.HTML("<p>Hello, world!</p>"),
    })
    
    • 1
    • 2
    • 3

    使用这种方法实现最为简单,但缺陷是在不修改代码的情况下该字段将固定转换为template.HTML类型,使用较为不灵活。

    注册自定义转义处理函数

    除了在执行Execute()前将文本转换类型外,还可以使用模版的Funcs()方法注册自定义函数。

    为了实现我们避免转义HTML文本的效果,我们先要定义一个函数用于处理将字符串转为template.HTML类型。例如我们定一个名为unescapeHTML的函数:

    func unescapeHTML(s string) template.HTML {
      return template.HTML(s)
    }
    
    • 1
    • 2
    • 3

    在定义转义处理函数后,我们需要使用Funcs()将其注册到模版中。需要注意,注册自定义函数需要在调用Parse()前进行。在注册时我们需要定义一个函数标识符,并在模版文本中使用。在下面例子中我们使用了名为unescapeHTML的函数标识符。

    tpl, err := template.
      New("example").
      Funcs(template.FuncMap{
        "unescapeHTML": unescapeHTML,
      }).
      Parse(content)
    if err != nil {
      // ...
    }
    buf := new(bytes.Buffer)
    tpl.Execute(buf, map[string]string{
      "Content": "<p>Hello, world!</p>",
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    另外在模版文本内容中,对于需要避免转义的部分需要使用上面定义的函数。为了进行对比,我们在示例中对两个区域分别使用了unescapeHTML进行标记以及不使用任何修改:

    <body>
      <main>
        <div>{{unescapeHTML .Content}}</div>
        <div>{{.Content}}</div>
      </main>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行后我们将得到:

    <body>
      <main>
        <div><p>Hello, world!</p></div>
        <div>&lt;p&gt;Hello, world!&lt;/p&gt;</div>
      </main>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    写在最后

    使用模版的自定义函数自定义转义处理方法虽相对将为复杂一些,但是在后续使用中较为灵活,只需要修改模版文件即可,而无需修改实现代码。

    html/template同样也提供了例如template.JStemplate.CSS等类型,用于Javascript或是CSS的处理。

    html/template包默认进行转义很大程度上避免了一些安全性的问题,例如潜在的XSS攻击等。在实际使用中,进行不转义处理后将存在安全性方面的风险,对于风险较高的使用场合需要另外考虑这方面的处理。

  • 相关阅读:
    再次尝试放出被屏蔽的百度蜘蛛网段
    GitHub标星百万的程序员转架构之路,竟被阿里用作内部晋升参考
    一步步来,如何高效优质的锻炼身体
    Java面试题02
    vmware NAT模式配置方式
    「Netflix Hollow系列」深入分析Hollow生产消费模型
    数据结构与算法【Java】08---树结构的实际应用
    某程序员发现 CSDN官方“漏洞”,立省¥10000+,抓紧薅吧
    leetcode 609. Find Duplicate File in System(找到相同的文件)
    鸿蒙Harmony应用开发—ArkTS声明式开发(鼠标事件)
  • 原文地址:https://blog.csdn.net/ghosind/article/details/125532470