I'm trying to fix a possible XSS vulnerability in WebApp (Flask) and I'm not sure what is the best way to prevent XSS without breaking functionality. For example, I have the following code block:
...
messages = db.execute("SELECT message, created_at FROM messages ORDER BY created_at DESC").fetchall()
messages_for_render = []
current_number = len(messages)
replace_str = re.compile("(guestbook)", re.IGNORECASE)
for message in messages:
text = replace_str.sub(r"<b>\1</b>", message['message'])
messages_for_render.append({
'number': current_number,
'text': text,
'created_at': message['created_at']
})
current_number -= 1
return render_template_string('''
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Guestbook{% endblock %}</h1>
{% endblock %}
{% block content %}
{% for message in messages_for_render %}
<div>
<h1> Message #{{ message.number }}</h1>
<p>{{ message.text | safe }}</p>
<small>Created at {{ message.created_at }}</small>
</div>
{% endfor %}
<a href={{ url_for('guestbook.add_message') }}>Add message</a>
{% endblock %}
''', messages_for_render=messages_for_render)
...
As you may see, message.text
should contain <b>guestbook</b>
, which should be correctly displayed.
If I'll try to remove | safe
to disable autoescape, then required tags will be disabled too (same for the render_template_string() -> render_template() replacement).
I could try to replace dangerous symbols, such as <>"'&
, manually, but I think there should be a more elegant solution.
Can anyone give me advice, what is the best way to deal with such cases?
Thanks!