Skip to main content

HTML sanitizer

Project description

https://travis-ci.org/matthiask/html-sanitizer.svg?branch=master

This is a whitelist-based and very opinionated HTML sanitizer that can be used both for untrusted and trusted sources. It attempts to clean up the mess made by various rich text editors and or copy-pasting to make styling of webpages simpler and more consistent. It builds on the excellent HTML cleaner in lxml to make the result both valid and safe.

HTML sanitizer goes further than e.g. bleach in that it not only ensures that content is safe and tags and attributes conform to a given whitelist, but also applies additional transforms to HTML fragments.

Goals

  • Clean up HTML fragments using a very restricted set of allowed tags and attributes.

  • Convert some tags (such as <span style="...">, <b> and <i>) into either <strong> or <em> (but never both).

  • Absolutely disallow all inline styles.

  • Normalize whitespace by removing repeated line breaks, empty paragraphs and other empty elements.

  • Merge adjacent tags of the same type (such as several <strong> or <h3> directly after each other.

  • Automatically remove redundant list markers inside <li> tags.

  • Clean up some uglyness such as paragraphs inside paragraphs or list elements etc.

  • Normalize unicode.

Usage

>>> from html_sanitizer import Sanitizer
>>> sanitizer = Sanitizer()  # default configuration
>>> sanitizer.sanitize('<span style="font-weight:bold">some text</span>')
'<strong>some text</strong>'

Settings

  • Bold spans and b tags are converted into strong tags, italic spans and i tags into em tags (if strong and em are allowed at all)

  • Inline styles and scripts will always be dropped.

  • A div element is used to wrap the HTML fragment for the parser, therefore div tags are not allowed.

The default settings are:

DEFAULT_SETTINGS = {
    'tags': {
        'a', 'h1', 'h2', 'h3', 'strong', 'em', 'p', 'ul', 'ol',
        'li', 'br', 'sub', 'sup', 'hr',
    },
    'attributes': {
        'a': ('href', 'name', 'target', 'title', 'id'),
    },
    'empty': {'hr', 'a', 'br'},
    'separate': {'a', 'p', 'li'},
    'add_nofollow': False,
    'autolink': False,
    'sanitize_href': html_sanitizer.sanitizer.sanitize_href,
    'element_preprocessors': [
        html_sanitizer.sanitizer.bold_span_to_strong,
        html_sanitizer.sanitizer.italic_span_to_em,
        html_sanitizer.sanitizer.tag_replacer('b', 'strong'),
        html_sanitizer.sanitizer.tag_replacer('i', 'em'),
    ],
    'element_postprocessors': [
    ],
    'is_mergeable': lambda e1, e2: True,
}

The keys’ meaning is as follows:

  • tags: A set() of allowed tags.

  • attributes: A dict() mapping tags to their allowed attributes.

  • empty: Tags which are allowed to be empty. By default, empty tags (containing no text or only whitespace) are dropped.

  • separate: Tags which are not merged if they appear as siblings. By default, tags of the same type are merged.

  • add_nofollow: Whether to add rel="nofollow" to all links.

  • autolink: Enable lxml’s autolinker. May be either a boolean or a dictionary; a dictionary is passed as keyword arguments to autolink.

  • sanitize_href: A callable that gets anchor’s href value and returns a sanitized version. The default implementation checks whether links start with a few allowed prefixes, and if not, returns a single hash (#).

  • element_preprocessors and element_postprocessors: Additional filters that are called on all elements in the tree. The tree is processed in reverse depth-first order. Under certain circumstances elements are processed more than once (search the code for backlog.append). Preprocessors are run before whitespace normalization, postprocessors afterwards.

  • is_mergeable: Adjacent elements which aren’t kept separate are merged by default. This callable can be used to prevent merging of adjacent elements e.g. when their classes do not match (lambda e1, e2: e1.get('class') == e2.get('class'))

Settings can be specified partially when initializing a sanitizer instance, but are still checked for consistency. For example, it is not allowed to have tags in empty that are not in tags, that is, tags that are allowed to be empty but at the same time not allowed at all. The Sanitizer constructor raises TypeError exceptions when it detects inconsistencies.

An example for an even more restricted configuration might be:

>>> from html_sanitizer import Sanitizer
>>> sanitizer = Sanitizer({
...     'tags': ('h1', 'h2', 'p'),
...     'attributes': {},
...     'empty': set(),
...     'separate': set(),
... })

The rationale for such a restricted set of allowed tags (e.g. no images) is documented in the design decisions section of django-content-editor’s documentation.

Django

HTML sanitizer does not depend on Django, but ships with a module which makes configuring sanitizers using Django settings easier. Usage is as follows:

>>> from html_sanitizer.django import get_sanitizer
>>> sanitizer = get_sanitizer([name=...])

Different sanitizers can be configured. The default configuration is aptly named 'default'. Example settings follow:

HTML_SANITIZERS = {
    'default': {
      'tags': ...,
    },
    ...
}

The 'default' configuration is special: If it isn’t explicitly defined, the default configuration above is used instead. Non-existing configurations will lead to ImproperlyConfigured exceptions.

The get_sanitizer function caches sanitizer instances, so feel free to call it as often as you want to.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

html-sanitizer-1.6.2.tar.gz (13.9 kB view details)

Uploaded Source

Built Distribution

html_sanitizer-1.6.2-py2.py3-none-any.whl (14.8 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file html-sanitizer-1.6.2.tar.gz.

File metadata

  • Download URL: html-sanitizer-1.6.2.tar.gz
  • Upload date:
  • Size: 13.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.18.4 setuptools/39.2.0 requests-toolbelt/0.8.0 tqdm/4.23.4 CPython/3.6.5

File hashes

Hashes for html-sanitizer-1.6.2.tar.gz
Algorithm Hash digest
SHA256 a0d33dc58838c28e8e150ee58096fbd5897dc531ca1b09f578a68968f9a03b22
MD5 492f6c1d23785f715b32eb0622df294b
BLAKE2b-256 9e671b4149acf742e053ed32d533d3b0c6a2fb0c0efac09c3d3a41e12014365e

See more details on using hashes here.

File details

Details for the file html_sanitizer-1.6.2-py2.py3-none-any.whl.

File metadata

  • Download URL: html_sanitizer-1.6.2-py2.py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.18.4 setuptools/39.2.0 requests-toolbelt/0.8.0 tqdm/4.23.4 CPython/3.6.5

File hashes

Hashes for html_sanitizer-1.6.2-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 6adcd402d71ae257e8a64691043a9011996e44888a4fb34b69a7e223150cd01d
MD5 c74ca096cf007bbf8ff486c0a9d7b406
BLAKE2b-256 ab3974f52a56a929e3aadb075ecb50cf8a44eaa9a2841a4488196d2b345d243b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page