OhMad
OhMad

Reputation: 7279

Django Template – Mark only certain HTML tags as safe

I have the following use case: a user should be able to enter in HTML input and it should be displayed as such. However, it can only contain <br>, <italic>, <strong>, <ul> or <li> tags.

I know about the safe filter, but that way it would allow every HTML input and be prone to XSS.

Any idea how I can solve this?

Thanks!

Upvotes: 2

Views: 772

Answers (2)

Gon&#231;alo Peres
Gon&#231;alo Peres

Reputation: 13582

As mentioned in the answer to this question, one can use bleach.

Start by defining a list of the tags one wants to allow by overriding the default ALLOWED_TAGS

ALLOWED_TAGS = ['br', 'italic', 'strong', 'ul', 'li']

Then, use bleach.clean() to remove any other HTML tags that are not allowed

user_input = '<p>an <strong>example</strong> for SO</p>'
cleaned_user_input = bleach.clean(user_input, tags=ALLOWED_TAGS)

This will remove the p tag from the user_input.

Upvotes: 1

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476493

We can make a validator that only allows certain tags, for example with BeautifulSoup:

from bs4 import BeautifulSoup
from bs4.element import Tag
from django.core.exceptions import ValidationError
from django.utils.deconstruct import deconstructible


@deconstructible
class HtmlValidator:
    def __init__(self, tags=()):
        self.tags = tags

    def validate(self, node):
        if isinstance(node, Tag):
            if node.name not in self.tags:
                raise ValidationError(f'Tag {node.name} is not a valid tag')
            for child in node:
                self.validate(child)

    def __call__(self, value):
        soup = BeautifulSoup(value, 'html.parser')
        for child in soup:
            self.validate(soup)

Then we can add such validator to the model:

class MyModel(models.Model):
    content = models.CharField(
        max_length=1024,
        validators=[HtmlValidator(tags={'br', 'italic', 'strong', 'ul', 'li'})],
    )
    # …

Upvotes: 0

Related Questions