一个 Golang 版本 XSS 过滤模块

go-xss 根据白名单过滤 HTML(防止 XSS 攻击)

go-xss is a module used to filter input from users to prevent XSS attacks

go-xss是一个用于对用户输入的内容进行过滤,以避免遭受 XSS 攻击的模块(( 什么是 XSS 攻击? )。主要用于论坛、博客、网上商店等等一些可允许用户录入页面排版、格式控制相关的 HTML 的场景,xss模块通过白名单来控制允许的标签及相关的标签属性,另外还提供了一系列的接口以便用户扩展,比其他同类模块更为灵活。

English | 中文文档

特性

  • 白名单控制允许的 HTML 标签及各标签的属性
  • 通过自定义处理函数,可对任意标签及其属性进行处理

性能

speed: 24MB/s

安装

go get -u github.com/feiin/go-xss

使用

import (
    "github.com/feiin/go-xss"
)


source := "link"

safeHtml := xss.FilterXSS(source,xss.XssOption{})
import (
    "github.com/feiin/go-xss"
)

source := "link"
x := xss.NewXSS(xss.XssOption{})
safeHtml := x.Process(source)

自定义过滤规则(options)

在调用 xss 进行过滤时,可通过options参数来设置自定义规则:

source := "link"

options := xss.XssOption{}
safeHtml := xss.FilterXSS(source,options)

如果不想每次都传入一个 options 参数,可以创建一个 XSS 实例:

source := "link"
options := xss.XssOption{}

x := xss.NewXSS(options)
safeHtml := x.Process(source)

白名单

通过 WhiteList 来指定,格式类型为: map[string][]string 。不在白名单上的标签将被过滤,不在白名单上的属性也会被过滤。以下是示例:

// 只允许a标签,该标签只允许href, title, target这三个属性
options.WhiteList = map[string][]string {
        "a":{"href","title","target"},
}
// 使用以上配置后,下面的HTML
// 大家好
// 将被过滤为
// 大家好

默认白名单参考 xss.GetDefaultWhiteList()

自定义匹配到标签时的处理方法

通过 OnTag 来指定相应的处理函数。以下是详细说明:

func onTag(tag, html string, options TagOption) *string {
    // tag是当前的标签名称,比如标签,则tag的值是'a'
  // html是该标签的HTML,比如标签,则html的值是''
  // options是一些附加的信息,具体如下:
  //   isWhite    boolean类型,表示该标签是否在白名单上
  //   isClosing  boolean类型,表示该标签是否为闭合标签,比如时为true
  //   position        integer类型,表示当前标签在输出的结果中的起始位置
  //   sourcePosition  integer类型,表示当前标签在原HTML中的起始位置
  // 如果返回一个字符串,则当前标签将被替换为该字符串
  // 如果返回nil,则使用默认的处理方法:
  //   在白名单上:  通过onTagAttr来过滤属性,详见下文
  //   不在白名单上:通过onIgnoreTag指定,详见下文
}

自定义匹配到标签的属性时的处理方法

通过 OnTagAttr 来指定相应的处理函数。以下是详细说明:

func OnTagAttr(tag, name, value string,isWhiteAttr bool) *string {
    // tag是当前的标签名称,比如标签,则tag的值是'a'
  // name是当前属性的名称,比如href="#",则name的值是'href'
  // value是当前属性的值,比如href="#",则value的值是'#'
  // isWhiteAttr是否为白名单上的属性
  // 如果返回一个字符串,则当前属性值将被替换为该字符串
  // 如果返回nil,则使用默认的处理方法
  //   在白名单上:  调用safeAttrValue来过滤属性值,并输出该属性,详见下文
  //   不在白名单上:通过onIgnoreTagAttr指定,详见下文
}

自定义匹配到不在白名单上的标签时的处理方法

通过 OnIgnoreTag 来指定相应的处理函数。以下是详细说明:

func OnIgnoreTag(tag, html string, options TagOption) *string {
    // 参数说明与onTag相同
  // 如果返回非nil,则当前标签将被替换为该字符串
  // 如果返回nil,则使用默认的处理方法(通过escape指定,详见下文)
}

自定义匹配到不在白名单上的属性时的处理方法

通过 OnIgnoreTagAttr 来指定相应的处理函数。以下是详细说明:

func OnIgnoreTagAttr(tag,name, value string,isWhiteAttr bool) *string {
  // 参数说明与onTagAttr相同
  // 如果返回一个字符串,则当前属性值将被替换为该字符串
  // 如果返回nil,则使用默认的处理方法(删除该属)
}

自定义 HTML 转义函数

通过 EscapeHtml 来指定相应的处理函数。以下是默认代码 (不建议修改) :

func EscapeHTML(html string) string {
    return regGT.ReplaceAllString(regLT.ReplaceAllString(html,"")
}

自定义标签属性值的转义函数

通过 SafeAttrValue 来指定相应的处理函数。以下是详细说明:

func SafeAttrValue(tag, name, value string) string {
// 参数说明与onTagAttr相同(没有options参数)
  // 返回一个字符串表示该属性值

}

自定义 CSS 过滤器

TODO

快捷配置

去掉不在白名单上的标签

通过 StripIgnoreTag 来设置:

  • true:去掉不在白名单上的标签
  • false:(默认),使用配置的escape函数对该标签进行转义 示例:

当设置 StripIgnoreTag = true时,以下代码

code:alert(/xss/);

过滤后将输出

code:alert(/xss/);

去掉不在白名单上的标签及标签体

通过 StripIgnoreTagBody 来设置:

nil
[]string{}
[]string{"tag1", "tag2"}

示例:

当设置 StripIgnoreTagBody = []string{"script"}时,以下代码

code:alert(/xss/);

过滤后将输出

code:

去掉 HTML 备注

通过 AllowCommentTag 来设置:

  • true:不处理
  • false:(默认),自动去掉 HTML 中的备注 示例:

当设置 AllowCommentTag = false 时,以下代码

code: END

过滤后将输出

code: END

应用实例

允许标签以 data-开头的属性

source := "
hello
"; html := xss.FilterXSS(source,xss.XssOption{ OnIgnoreTagAttr: func(tag,name, value string,isWhiteAttr bool) *string { if len(name)>=5 && name[0:5] == "data-" { ret := name + "=\"" + xss.EscapeAttrValue(value)+"\"" return &ret } return nil }, }) fmt.Printf("%s\nconvert to:\n%s", source, html);

运行结果:

hello
convert to:
hello

允许名称以 x-开头的标签

source := "hewwww";

    html := xss.FilterXSS(source,xss.XssOption{
            OnIgnoreTag: func(tag, html string, options xss.TagOption) *string {
                if len(tag)>=2 && tag[0:2] == "x-" {
                    return &html;
                }
                return nil
            },
    })
    fmt.Printf("%s\nconvert to:\n%s", source, html);

运行结果

hewwww
convert to:
hewwww

分析 HTML 代码中的图片列表

source := "abcd"
    var list []string
    html := xss.FilterXSS(source,xss.XssOption{
            OnTagAttr: func(tag, name, value string ,isWhiteAttr bool) *string {
                if tag == "img" && name == "src" {
                    list = append(list,value)
                }
                return nil
            },
    })
    fmt.Printf("image list:\n%s", strings.Join(list, ","));

运行结果:

image list:
img1, img2, img3, img4

去除 HTML 标签(只保留文本内容)

source := "helloalert(/xss/);end"
    html := xss.FilterXSS(source,xss.XssOption{
            WhiteList:map[string][]string{},  // // empty, means filter out all tags
            StripIgnoreTag:true, // filter out all HTML not in the whitelist
            StripIgnoreTagBody:[]string{"script"}, // the script tag is a special case, we need
    })
    fmt.Printf("text: %s", html);

运行结果:

text: helloend

Inspirations

License

MIT