To have a simple and secure editor for text fields of a django app, I have this snippet to sanitize input HTML into django code:
from bs4 import BeautifulSoup
def sanitize_html(value):
tag_whitelist = ['img','b','strong','blockquote', 'a']
attr_whitelist = ['src', 'alt', 'width', 'height', 'href','class']
soup = BeautifulSoup(value)
for tag in soup.find_all():
if tag.name.lower() in tag_whitelist:
tag.attrs = { name: value for name, value in tag.attrs.items()
if name.lower() in attr_whitelist }
else:
tag.unwrap()
# scripts can be executed from comments in some cases
try:
comments = soup.find_all(text=lambda text:isinstance(text, Comment))
for comment in comments:
comment.extract()
except:
pass
return unicode(soup)
I have also blacklisted entering javascript
in model fields using this method:
BADLIST = ['javascript']
def no_js (text):
if any(e in text for e in BADLIST):
raise ValidationError("Your text contains bad words!")
else:
return True
On the other hand, in template I need to use {{text| safe}}
to allow healthy HTML tags to be displayed.
So I'm wondering with these constraint, whether the input is still vulnerable to cross-site scripting (XSS)? And if so, how to fix it?