敏感词过滤是一种在网站、应用程序或平台中实现内容审查的技术,用于阻止用户发布包含不适当、非法或不符合政策的内容。我们在实际的网站运营过程中,往往需要担心某些用户发布的内容中包含敏感词汇,这些词汇往往会导致我们的网站被用户举报,甚至被服务器运营商封禁、被相关部门约谈、罚款等。为了防止这种情况发生,我们需要对敏感词汇进行过滤。
敏感词过滤的实现涉及多个步骤,既包括技术实现,也包括策略制定。以下以安企CMS的敏感词过滤设计为例,展开说明。
定义敏感词库
敏感词库的构成,一般包含涉及SE情的、涉及政治的、涉及FAN动暴力的、涉及广告法的词汇。根据我们网站的不同定义,可以收集集中一部分获取全部的词汇。一般我们可以从网上下载或手动收集这些词汇。在敏感词库的收集方面,安企CMS设计成了手动收集+系统同步双模式。默认系统没有敏感词,可以选择从官网同步官网预设好的敏感词库,也可以手动添加自定义的敏感词。
敏感词过滤的算法设计
针对日常的企业网站,我们不必要采用上下文分析、语义分析等 AI 算法。为了简便起见,我们可以使用最常见,也是最简单是的关键词匹配算法,为了更大的适应规则,我们还可以增加使用正则匹配类的模糊匹配算法来实现。安企CMS 采用的就是关键词匹配 + 正则模糊匹配双模式进行处理。具体的替换代码如下:
具体代码是 GoLang 代码,因为 安企CMS 是 Go 语言开发,因此代码以 Go 语言为例。
func ReplaceSensitiveWords(content []byte, sensitiveWords []string) []byte {
// 如果敏感词库为空,或内容为空,直接返回
if len(sensitiveWords) == 0 || len(content) == 0 {
return content
}
// 顶一个结构体,用于存储替换结果
type replaceType struct {
Key []byte
Value []byte
}
var replacedMatch []*replaceType
numCount := 0
//忽略所有html标签的属性,这是为了防止将标签属性替换成为*,导致页面出错
reg, _ := regexp.Compile("(?i)<!?/?[a-z0-9-]+(\\s+[^>]+)?>")
content = reg.ReplaceAllFunc(content, func(s []byte) []byte {
key := []byte(fmt.Sprintf("{$%d}", numCount))
replacedMatch = append(replacedMatch, &replaceType{
Key: key,
Value: s,
})
numCount++
return key
})
// 替换所有敏感词为星号
for _, word := range sensitiveWords {
if len(word) == 0 {
continue
}
if bytes.Contains(content, []byte(word)) {
content = bytes.ReplaceAll(content, []byte(word), bytes.Repeat([]byte("*"), utf8.RuneCountInString(word)))
} else {
// 支持正则表达式替换,定义正则表达式以{开头}结束,如:{[1-9]\d{4,10}}
if strings.HasPrefix(word, "{") && strings.HasSuffix(word, "}") && len(word) > 2 {
// 移除首尾花括号
newWord := word[1 : len(word)-1]
re, err := regexp.Compile(newWord)
if err == nil {
content = re.ReplaceAll(content, bytes.Repeat([]byte("*"), utf8.RuneCountInString(word)))
}
continue
}
}
}
// 将上面忽略的html标签属性还原回来
for i := len(replacedMatch) - 1; i >= 0; i-- {
content = bytes.Replace(content, replacedMatch[i].Key, replacedMatch[i].Value, 1)
}
return content
}
敏感词替换的时机
敏感词替换的可以在以下几种时机下进行:提交实时过滤:用户在提交内容时,系统会自动检测并过滤敏感词。
批量过滤:系统定时扫描数据库中的内容,对敏感词进行批量过滤。
显示时过滤:在显示内容的时候,系统会自动检测并过滤敏感词。
安企CMS 使用主要使用的是第三种时机方案。在页面渲染的时候,系统自动过滤敏感词。这也是为了考虑有不同的数据输入来源,以及敏感词库的动态更新,在提交时实时过滤的话,后来补充的敏感词就无法生效,而批量过滤也可能经常因为不及时导致的敏感词失效。因此在显示时过滤处理更严谨一些,虽然这么做会牺牲一些性能。
为了实现显示时过滤敏感词,安企CMS重写了 ExecuteWriter 输出函数,具体的代码如下:
func (s *DjangoEngine) ExecuteWriter(w io.Writer, filename string, _ string, bindingData interface{}) error {
// 如果开启了debug模式,每次渲染的时候,重新解析模板。
if s.reload {
if err := s.LoadStart(true); err != nil {
return err
}
}
ctx := w.(iris.Context)
currentSite := provider.CurrentSite(ctx)
if tmpl := s.fromCache(currentSite.Id, filename); tmpl != nil {
data, err := tmpl.ExecuteBytes(getPongoContext(bindingData))
if err != nil {
return err
}
// 对data进行敏感词替换
data = currentSite.ReplaceSensitiveWords(data)
buf := bytes.NewBuffer(data)
_, err = buf.WriteTo(w)
return err
}
// 如果模板不存在,返回错误
return view2.ErrNotExist{Name: filename, IsLayout: false, Data: bindingData}
}
以上的敏感词过滤的思路和实践。在实际使用过程中,我们应该根据实际需求进行优化和调整。在机器自动过滤的基础上,增加人工审核部分内容,定期巡查,特别是那些容易产生歧义或涉及深度语义分析的内容。
敏感词过滤是一个复杂且动态的过程,既需要高效的技术手段,也需要灵活应变的策略以适应不断变化的语言环境和政策要求。希望以上内容能帮助到您。