1.背景:网页若被javascript代码篡改,将发生一些不好的事情,比如在网页中插入如下打广告代码:
<script>setInterval(function(){alert('代购驾照分,有意请联系QQ:12345678.(每隔两秒弹出一次)')},2000);</script>
原网页内容:Java学习经典案例,优秀代码集锦!请勿错过。
新网页内容:Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系QQ:13452456.(每隔两秒弹出一次)')},2000);</script>。
将新网页内容保存到一个html文件中,然后访问,效果如下(每隔两秒弹出一次广告):
2. 处理上述问题可以责任链模式,每个过滤器负责自己过滤的职责,如果有过滤任务,就过滤,不过滤就放行资源。
创建自定义过滤器过滤掉javascript代码和隐藏7位以上的QQ号(QQ号一般都比较长,隐藏7位以上长度的数字,可避免将其它数字也隐藏掉)
过滤器接口 MyFilter:
public interface MyFilter {
/**
* @param word 过滤前字符
* @param ret 过滤后结果
* @param filter 自定义过滤器链
*/
public abstract void doFilter(String word,String[] ret,MyFilterChain filter);
}
过滤javascript代码的过滤器JavascriptFilter
/**
* JavaScript过滤:过滤
*
* @author kick
*/
public class JavascriptFilter implements MyFilter {
@Override
public void doFilter(String word, String[] ret, MyFilterChain filterChain) {
if (ret.length > 0 && !"".equals(ret[0])) {
word = ret[0];// 将上一次过滤后的结果作为本次的过滤数据(比如上一次进行了敏感词汇过滤,将去掉敏感词汇后的结果作为待过滤数据)
}
//本次过滤数据操作
try {
//当网页内容出现 <script> </script>关键字时才过滤小于号和打于号
if (word.matches("^.*(</?script>).*$")) {//正则表达式,匹配<script>或</script>
ret[0] = word.replaceAll("<", "<").replaceAll(">", ">")
+ "\n-1.调用JavascriptFilter-网页中的javascript代码已替换";
}
filterChain.doFilter(word, ret, filterChain);//正常过滤后放行,让过滤器链执行下一个过滤器
} catch (Exception e) {
e.printStackTrace();
return;//过滤时发生异常,不执行后续过滤器,直接返回
}
}
}
隐藏含有QQ关键字的文本中连续7位及以上的数字
/**
* 敏感词汇过滤(当存在大小写QQ关键字并且含有连续7位及以上数字时,将数字隐藏)
* @author kick
*/
public class SensitiveFilter implements MyFilter {
@Override
public void doFilter(String word, String[] ret, MyFilterChain filterChain) {
if (ret.length > 0 && !"".equals(ret[0])) {
word = ret[0];//将上一次过滤结果作为本次过滤数据
}
try {
if (word.contains("QQ") || word.contains("qq")) {
ret[0] = word.replaceAll("\\d{7,}", "*******")
+ "\n-2.调用SensitiveFilter-网页中含有qq数字,已将7位以上连续数字隐藏";
}
filterChain.doFilter(word, ret, filterChain);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
过滤器链
/**
* 过滤器链:可添加多个过滤器,并使用它们的过滤功能
* @author kick
*/
public class MyFilterChain implements MyFilter{//实现MyFilter接口,在遵循MyFilter方法规范下扩展了过滤功能,简单说就是可以使用过滤功能了
private List<MyFilter> filters =new ArrayList<MyFilter>();//过滤器链,存储所有过滤器
int index=-1;//定位过滤器执行位置
/**
* 向过滤器链添加过滤器
* @param filter 待添加的过滤器
* @return 过滤器链本身(不返回值也可以,返回本身,主要是为了链式编程,在添加多个过滤器时再次访问本身的某个方法(添加或移除),
* 不明白的看后续测试代码)
*/
public MyFilterChain addFilter(MyFilter filter) {
filters.add(filter);
return this;
}
/**
* 在过滤器链中移除已添加的过滤器
* @param filter 已在过滤器链中的过滤器
* @return 过滤器链本身(同上,用于移除多个过滤器时的链式编程)
*/
public MyFilterChain removeFilter(MyFilter filter){
filters.remove(filter);
return this;
}
@Override
public void doFilter(String word,String[] ret,MyFilterChain filterChain) {
if(index < filters.size()-1){
index++;
filters.get(index).doFilter(word, ret, this);
}else{
index = -1;
}
}
}
3.模拟测试
使用字符串badHtml模拟被篡改的网页内容
使用字符串noQQHtml模拟只有javascript代码,而无QQ关键字时,过滤器仍能正常运行,且只过滤javascript代码,而不隐藏其中7位及以上的数字。
public static void main(String[] args) {
String badHtml="Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系QQ:13452456.(每隔两秒弹出一次)')},2000);</script>";
String noQQHtml="Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系:13452456.(每隔两秒弹出一次)')},2000);</script>";
MyFilter javascriptFilter = new JavascriptFilter();
MyFilter sensitiveFilter = new SensitiveFilter();
MyFilterChain filterChain = new MyFilterChain();
filterChain.addFilter(javascriptFilter)
.addFilter(sensitiveFilter);
String[] returnHtml={""};//过滤后字符串接收数组
filterChain.doFilter(badHtml,returnHtml,filterChain);
System.out.println("过滤前网页内容:\n"+badHtml);
System.out.println("过滤后网页内容:\n"+returnHtml[0]);
System.out.println("-------------------------------------------");
String[] noQQReturn={""};//过滤后字符串接收数组
filterChain.doFilter(noQQHtml, noQQReturn, filterChain);
System.out.println("无QQ号过滤前网页内容:\n"+noQQHtml);
System.out.println("无QQ号过滤后网页内容:\n"+noQQReturn[0]);
}
测试结果:
过滤器顺序跟过滤器链中集合元素顺序有关(先添加哪个过滤器就先执行哪个过滤功能)
过滤前网页内容:
Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系QQ:13452456.(每隔两秒弹出一次)')},2000);</script>
过滤后网页内容:
Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系QQ:*******.(每隔两秒弹出一次)')},2000);</script>
-1.调用JavascriptFilter-网页中的javascript代码已替换
-2.调用SensitiveFilter-网页中含有qq数字,已将7位以上连续数字隐藏
-------------------------------------------
无QQ号过滤前网页内容:
Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系:13452456.(每隔两秒弹出一次)')},2000);</script>
无QQ号过滤后网页内容:
Java学习经典案例,优秀代码集锦!请勿错过。<script>setInterval(function(){alert('代购驾照分,有意请联系:13452456.(每隔两秒弹出一次)')},2000);</script>
-1.调用JavascriptFilter-网页中的javascript代码已替换