XSS脚本攻击防御(Antisamy)(下)

上篇写了怎么使用antisamy防御xss脚本攻击,下篇简单分析一下antisamy过滤的原理。

基础步骤的分析

从上篇的最基础的实现逻辑分析具体的实现,下面这段最基础实现非常好理解,看注释就能知道实现步骤。

//定义过滤的策略
Policy policy = Policy.getInstance("file"); //此处的file指使用的策略文件,如antisamy-ebay.xml
//对html输入进行过滤
Antisamy antisamy = new Antisamy();
CleanResult cr = antisamy.scan(innerHtml,policy);
//输出过滤后安全的html或异常信息
String cleanHtml = cr.getCleanHTML();
String errMsg = cr.getErrorMessages();

项目源码

重点是解析过程。在网上查阅了一些资料,配合阅读了项目的源码。确认策略是将html解析成dom树,然后扫描,源码中的代码如下

扫描流程

  public CleanResults scan(String html)
    throws ScanException
  {
    if (html == null) {
      throw new ScanException(new NullPointerException("Null input"));
    }

    this.errorMessages.clear();
    int maxInputSize = this.policy.getMaxInputSize();

    if (maxInputSize < html.length()) {
      addError("error.size.toolarge", new Object[] { Integer.valueOf(html.length()), Integer.valueOf(maxInputSize) });
      throw new ScanException((String)this.errorMessages.get(0));
    }

    this.isNofollowAnchors = this.policy.isNofollowAnchors();
    this.isValidateParamAsEmbed = this.policy.isValidateParamAsEmbed();

    long startOfScan = System.currentTimeMillis();
    try
    {
      CachedItem cachedItem = (CachedItem)cachedItems.poll();
      if (cachedItem == null) {
        cachedItem = new CachedItem();
      }

      html = stripNonValidXMLCharacters(html, cachedItem.invalidXmlCharMatcher);

      DOMFragmentParser parser = cachedItem.getDomFragmentParser();
      try
      {
        parser.parse(new InputSource(new StringReader(html)), this.dom);
      } catch (Exception e) {
        throw new ScanException(e);
      }

      processChildren(this.dom, 0);

      String trimmedHtml = html;

      StringWriter out = new StringWriter();

      OutputFormat format = getOutputFormat();

      HTMLSerializer serializer = getHTMLSerializer(out, format);
      serializer.serialize(this.dom);

      String trimmed = trim(trimmedHtml, out.getBuffer().toString());

      Callable cleanHtml = new Callable(trimmed) {
        public String call() throws Exception {
          return this.val$trimmed;
        }
      };
      this.results = new CleanResults(startOfScan, cleanHtml, this.dom, this.errorMessages);

      cachedItems.add(cachedItem);
      return this.results;
    }
    catch (SAXException e)
    {
      throw new ScanException(e);
    }
    catch (IOException e) {
      throw new ScanException(e);
    }
  }

这段代码逻辑上比较清楚,简单的梳理一下:

  1. 确定输入的html不为空,为空的话抛出错误
  2. 确定输入的html长度不超过最大值,超出的话抛出错误
  3. 将html中的低价打印字符过滤掉(防止解析失败)
  4. 将html解析成dom树
  5. 处理dom树返回干净的html

html解析成dom的流程

代码中间解析成dom树的代码,查阅了相关资料,思路是这样的:

4 遍历dom树进行以下处理:

4.1 判断深度是否达到250,是返回异常

4.2 判断节点是否为comment,特殊处理后返回。

4.2.1 判断是否显示comment,否则删除comment节点

4.2.2 如果需要显示节点,则过滤节点的数据
4.3 判断节点是否为空元素,根据设置判断是否需要删除节点。

4.4 判断节点是否为CDATA,过滤节点数据

4.4.1 输出异常,同时创建text节点代替CDATA节点。
4.5 判断是否为ProcessingInstruction,是删除该节点

4.6 获取当前节点的tagRule,根据tagRule规则进行不同处理

4.6.1 判断是否使用默认的tagRule

4.6.2 要么encode节点(节点内容进行编码)

4.6.3 要么filter节点(删除节点,保留节点子节点)

4.6.4 要么validate节点

 对style节点进行特殊处理

 对其他节点的属性一个一个验证,如果发现校验失败,根据配置,进行以下处理:

4.6.4.1 removeTag :删除当前元素

4.6.4.2 filterTag : 过滤当前元素

4.6.4.3 encodeTag : 编码元素

4.6.4.4 remoteAttr: 默认配置,删除属性

4.6.5 要么truncate节点(删除节点属性,以及删除子节点中非text类型的节点)

4.6.6 要么删除节点(包括子节点都进行删除)

如果仅仅为了使用项目过滤文本,可以不用过分关注解析细节,了解其流程即可。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值