makedown过滤标签解决黑产内容通过<>规避词库检测的问题
【需求背景】
用户发布的内容中包含富文本内容,包括a标签,img标签等,为了提升词库检测的准确性,目前在做词库检测之前,通过hutool的HtmlUtil.cleanHtmlTag将待检测文本进行过滤。
但cleanHtmlTag未校验标签的合法性,会存在误操作,比如:会将所有"<“和”>"包裹的内容全部过滤,导致被黑产利用发布违规内容。
例如:<英超比赛在哪押注{C><网-Ag886.cn-网>#<英超比赛在哪押注{d英超比赛在哪押注><英超比赛在哪押注{H英超比赛在哪押注>
【需求详情】
在做词库检测之前,仅过滤合法的html标签,规避被黑产利用的问题
【实现方式】
通过调研发现有多款库可以实现html过滤。比如java清理html以封装好的库有三种分别是HtmlUtil.cleanHtmlTag (hutool),HtmlUtils.htmlEscape (spring),Jsoup.parse("").text() (jsoup)
前两都是对尖括号来进行清理html标签的,而jsoup可以更加html标签来清理html标签,但是也会有误杀比如<123><123>就可以但是<中文><中文>就不行!
所以并不满足当前开发的需求,所以我就自己实现了一个满足需求的html清理库,主要思路是先过滤无法用正则表达式清除的HTML标签,
第一步替换掉html标签里面的像Style,class,src.href等等这样的内容
第二步去除空格
第三步移除掉向,
,
,
,标签
第四步 匹配html标签,例如"xxx
"这种格式第五步 针对多个标签嵌套的情况进行处理
* 比如 <p><a href='https://itunes.apple.com/'>违规内容</a></p>
* 预处理并且正则匹配完之后结果是 <a>违规内容
* 需要手工移除掉前面的起始标签
最后只需要调用getResultsFromHtml就可以清理掉了
过滤代码
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlFilterUtil {
/**
* 替换掉html标签里面的像Style,class,src.href等等这样的内容
*
* @param content
* @return
*/
public static String replaceTagContent(String content) {
List<String> regExArray = new ArrayList<>();
String[] regExTextArray ={"style","src","href","class","data-origin","data-type"};
for(String regExText:regExTextArray){
regExArray.add(regExText+"=\'(.*?)\'");
regExArray.add(regExText+"=\"(.*?)\"");
}
if (content == null || content.length() == 0) {
return content;
}
for(String regEx : regExArray){
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(content);
if (m.find()) {
content = m.replaceAll("");
}
}
return content;
}
/**
* 移除掉向<img/>,<h1>,<h2>,<h3>,标签
*
* @param src
* @return
*/
public static String removeAllTagList(String src) {
List<String> regExArray = new ArrayList<>();
String[] regExHtextArray ={"h1","h2","h3","h4","h5"};
for(String regExHtext:regExHtextArray){
regExArray.add("<"+regExHtext+">");
regExArray.add("</"+regExHtext+">");
}
String[] regExTextArray ={"img","a","div","span"};
for(String regExText:regExTextArray){
regExArray.add("<"+regExText+"/>");
}
for(String regEx:regExArray){
if (src != null && !src.isEmpty()) {
src = src.replaceAll(regEx, "");
}
}
return src;
}
/**
* 针对多个标签嵌套的情况进行处理
* 比如 <p><a href='https://itunes.apple.com/'>违规内容</a></p>
* 预处理并且正则匹配完之后结果是 <a>违规内容
* 需要手工移除掉前面的起始标签
* @param content
* @return
*/
public static String replaceStartTag(String content) {
if (content == null || content.length() == 0) {
return content;
}
String regEx = "<[a-zA-Z]*?>([\\s\\S]*?)";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(content);
if (m.find()) {
content = m.replaceAll("");
}
return content;
}
/**
* 匹配html标签,例如"xxx</p>"这种格式
*/
private static Pattern HTML_TAG_PATTERN_rigth = Pattern.compile("([\\s\\S]*?)</[a-zA-Z]*?>");
/**
* 获取html中的数据
* @param htmlString
* @return
*/
public static String getResultsFromHtml(String htmlString) {
htmlString = "<p>"+htmlString+"</p>";
String results = "";
// 数据预处理
htmlString = replaceTagContent(htmlString).replace(" ", "");//同时去除空格
htmlString = removeAllTagList(htmlString);
if (htmlString != null && htmlString.length() > 0) {
Matcher imageTagMatcher = HTML_TAG_PATTERN_rigth.matcher(htmlString);
// 针对多个并列的标签的情况
while (imageTagMatcher.find()) {
String result = "";
// group(1)对应正则表达式中的圆括号括起来的数据
result = imageTagMatcher.group(1).trim();
// 针对多个标签嵌套的情况进行处理
if (result != null && result.length() > 0) {
result = replaceStartTag(result);
}
results+=result;
}
}
return results;
}
}