Django Template – Mark only certain HTML tags as safe

Viewed 23

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!

1 Answers

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'})],
    )
    # …
Related