Edgewall Software

Changeset 7658


Ignore:
Timestamp:
Nov 8, 2008, 7:24:00 PM (15 years ago)
Author:
Jonas Borgström
Message:

0.11-stable: Improved HTML sanitizer to detect and stop possible phishing attempts. Reported by Simon Willison.

Location:
branches/0.11-stable/trac
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/0.11-stable/trac/util/html.py

    r6904 r7658  
    1515
    1616from genshi import Markup, escape, unescape
    17 from genshi.core import stripentities, striptags
     17from genshi.core import stripentities, striptags, START, END
    1818from genshi.builder import Element, ElementFactory, Fragment
     19from genshi.filters.html import HTMLSanitizer
    1920
    20 __all__ = ['escape', 'unescape', 'html', 'plaintext']
     21__all__ = ['escape', 'unescape', 'html', 'plaintext', 'TracHTMLSanitizer']
     22
     23
     24class TracHTMLSanitizer(HTMLSanitizer):
     25
     26    UNSAFE_CSS = ['position']
     27
     28    def __init__(self):
     29        safe_attrs = HTMLSanitizer.SAFE_ATTRS | set(['style'])
     30        super(TracHTMLSanitizer, self).__init__(safe_attrs=safe_attrs)
     31
     32    def sanitize_css(self, text):
     33        decls = []
     34        text = self._strip_css_comments(self._replace_unicode_escapes(text))
     35        for decl in filter(None, text.split(';')):
     36            decl = decl.strip()
     37            if not decl:
     38                continue
     39            try:
     40                prop, value = decl.split(':', 1)
     41            except ValueError:
     42                continue
     43            if not self.is_safe_css(prop.strip().lower(), value.strip()):
     44                continue
     45            is_evil = False
     46            if 'expression' in decl:
     47                is_evil = True
     48            for match in re.finditer(r'url\s*\(([^)]+)', decl):
     49                if not self.is_safe_uri(match.group(1)):
     50                    is_evil = True
     51                    break
     52            if not is_evil:
     53                decls.append(decl.strip())
     54        return decls
     55
     56    def __call__(self, stream):
     57        """Remove input type="password" elements from the stream
     58        """
     59        suppress = False
     60        for kind, data, pos in super(TracHTMLSanitizer, self).__call__(stream):
     61            if kind is START:
     62                tag, attrs = data
     63                if (tag == 'input' and
     64                    attrs.get('type', '').lower() == 'password'):
     65                    suppress = True
     66                else:
     67                    yield kind, data, pos
     68            elif kind is END:
     69                if not suppress:
     70                    yield kind, data, pos
     71                suppress = False
     72            else:
     73                yield kind, data, pos
     74
     75    def is_safe_css(self, prop, value):
     76        """Determine whether the given css property declaration is to be
     77        considered safe for inclusion in the output.
     78        """
     79        if prop in self.UNSAFE_CSS:
     80            return False
     81        # Negative margins can be used for phishing
     82        elif prop.startswith('margin') and '-' in value:
     83            return False
     84        return True
    2185
    2286
  • branches/0.11-stable/trac/wiki/formatter.py

    r7619 r7658  
    2727from genshi.builder import tag, Element
    2828from genshi.core import Stream, Markup, escape
    29 from genshi.filters import HTMLSanitizer
    3029from genshi.input import HTMLParser, ParseError
    3130from genshi.util import plaintext
     
    3938from trac.util.text import shorten_line, to_unicode, \
    4039                           unicode_quote, unicode_quote_plus
     40from trac.util.html import TracHTMLSanitizer
    4141from trac.util.translation import _
    4242
     
    8989                              'Span': self._span_processor}
    9090
    91         self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
    92                                         set(['style']))
     91        self._sanitizer = TracHTMLSanitizer()
    9392       
    9493        self.processor = builtin_processors.get(name)
Note: See TracChangeset for help on using the changeset viewer.