Skip to content

Sanitizing filter broken in 0.90 #72

Closed

Description

@gsnedders

http://code.google.com/p/html5lib/issues/detail?id=162

Reported by [email protected], Oct 10, 2010

DESCRIPTION

Consider the following interaction with html5lib 0.90:

    >>> from html5lib import html5parser, serializer, treebuilders, treewalkers
    >>> p = html5parser.HTMLParser(tree = treebuilders.getTreeBuilder('dom'))
    >>> dom = p.parse("""<body onload="sucker()">""") 
    >>> s = serializer.htmlserializer.HTMLSerializer(sanitize = True)
    >>> ''.join(s.serialize(treewalkers.getTreeWalker('dom')(dom)))
    u'<body onload=sucker()>'

This is clearly incorrect: the onload attribute should have been removed by the sanitizer during the serialization.

ANALYSIS

The problem is that there are two sanitizers: a tokenizing sanitizer in html5lib.sanitizer, and a sanitizing filter in html5lib.filter.sanitizer. To avoid duplication of code, these two sanitizers inherit from the class HTMLSanitizerMixin and both call that class's function sanitize_token.

Unfortunately, the format of tokens differs between tokenization and filtering. During tokenization, a token looks like this:

    >>> from html5lib import tokenizer
    >>> next(iter(tokenizer.HTMLTokenizer("""<body onload="sucker()">""")))
    {'selfClosing': False, 'data': [[u'onload', u'sucker()']], 'type': 3, 'name': u'body', 'selfClosingAcknowledged': False}

But during filtering, tokens look like this:

    >>> list(iter(treewalkers.getTreeWalker('dom')(dom)))[3]
    {'namespace': u'http:/​/​www.w3.org/​1999/​xhtml', 'type': 'StartTag', 'name': u'body', 'data': [(u'onload', u'sucker()')]}

When the sanitizing filter passes its token to the sanitize_token method of HTMLSanitizerMixin, nothing happens, because sanitize_token is expecting 'type' to be an integer.

OBSERVATION

Having two very similar but subtly different data formats for the same data type is dangerous: how many other incompatibilities are there?

WORKAROUND

I am working around this problem as follows: when I need to apply a sanitizing filter to a DOM tree, instead I do the following:

  1. Serialize the DOM to HTML without sanitization.
  2. Re-parse the HTML from step 1, using the sanitizing tokenizer.

Activity

  1. gsnedders commented on Jun 26, 2013

    @gsnedders
    MemberAuthor

    So the status is:

    • We only support sanitizing at the tokenizer level.
    • We support and are totally broken sanitizing at the filter level (and sometimes die, sometimes don't).

    My gut says the filter level is the right level for the sanitizer to be operating (the middle of the parser doesn't make much sense, as what you really want to do is post-process the tree to remove what you dislike). I think we should probably goes as far as to remove the ability to change the tokenizer. The big downside of that, obviously, is that we go from the sanitizer only working as a tokenizer in 1.0b1 to that being unsupported and only working as a filter in 1.0b2…

    Thoughts, @jgraham, @garethrees, @jsocol?

  2. gsnedders commented on Jun 26, 2013

    @gsnedders
    MemberAuthor

    #24 has some relevance, but given duck-typing doesn't help much.

  3. garethrees commented on Jun 27, 2013

    @garethrees
  4. gsnedders commented on Jun 27, 2013

    @gsnedders
    MemberAuthor

    Oops! Sorry! Attempt two: Thoughts, @gareth-rees, on the above?

  5. jsocol commented on Jun 27, 2013

    @jsocol

    Ostensibly I agree that the filters are the more "correct" place to do sanitization, even if it means huge changes in bleach for 1.0, but I haven't really done it that way so my one question is: do filters enable both dropping the tag completely (with or without any content) and replacing it with an escaped version (e.g. &lt;script&gt;)?

  6. gsnedders commented on Jun 27, 2013

    @gsnedders
    MemberAuthor

    It's much easier to do with filters, as you're guaranteed a matching start tag and an end tag for each node, so you can maintain a simple stack to drop content. Obviously with tokenizers you either have to reimplement half the parser or accept you'll never get it quite right.

  7. added a commit that references this issue on Aug 27, 2013
    85256cf
  8. added a commit that references this issue on May 19, 2014
    0fd13c6
  9. kurtmckee commented on May 4, 2015

    @kurtmckee

    Howdy! I'm working to migrate the HTML sanitizer in feedparser to rely on html5lib. However, some of the feedparser unit tests are triggering the TypeError bug referenced in #68. If @gsnedders has written viable code to resolve this, would it be possible to coordinate feedparser's migration with the integration of the fix for this?

  10. gsnedders commented on May 5, 2015

    @gsnedders
    MemberAuthor

    @kurtmckee the fix for that is for currently to use the sanitizer as a filter when tokenizing and not when serializing; this will change once #72 gets fixed (which is PR #110) as then you'll use the sanitizer as a filter when serializing and not when tokenizing.

  11. added a commit that references this issue on Nov 25, 2015
    80a1425
  12. modified the milestones: 1.0, 0.99999999 on May 8, 2016
  13. added 8 commits that reference this issue on May 9, 2016
    f66e100
    08a5eca
    95a0be3
    42fde37
    d4abff1
    393f86a
    62ce217
    28bf43b
  14. added 3 commits that reference this issue on May 17, 2016
    516227e
    f582c58
    a2917e9
  15. rando305 commented on Nov 18, 2016

    @rando305

    Any chance someone could write replacement code for the following?

    from html5lib import sanitizer

    sanitizer.HTMLSanitizer.acceptable_elements.extend(settings.TEXT_ADDITIONAL_TAGS)

    This would really help me out. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions