Python 为什么Jinja nl2br过滤器会溢出<;br>';s但不是<;p>';s
我正在尝试实现JinjaPython 为什么Jinja nl2br过滤器会溢出<;br>';s但不是<;p>';s,python,regex,flask,jinja2,Python,Regex,Flask,Jinja2,我正在尝试实现Jinjanl2br过滤器。它工作正常,只是它添加的正在转义。这对我来说很奇怪,因为没有被转义,它们都在同一个字符串中 我正在使用flask,因此Jinjaautoescape已启用。当我发现说autoescape和escape(value)可能会导致双重转义时,我真的很有希望,但是删除escape()没有帮助 这是我修改过的代码及其输出: @app.template_filter() @evalcontextfilter def nl2br(eval_ctx, value):
nl2br
过滤器。它工作正常,只是它添加的
正在转义。这对我来说很奇怪,因为
没有被转义,它们都在同一个字符串中
我正在使用flask,因此Jinjaautoescape
已启用。当我发现说autoescape
和escape(value)
可能会导致双重转义时,我真的很有希望,但是删除escape()
没有帮助
这是我修改过的代码及其输出:
@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
result = u'\n\n'.join(u'<p>%s</p>' % escape(p.replace(u'\r\n', u'<br>\n')) for p in _paragraph_re.split(value))
if eval_ctx.autoescape:
result = Markup(result)
return result
输出:
<p>1<br>
2</p>
<p>3<br>
4</p>
<p>5<br>
6<br>
7</p>
1br
二,
3br
四,
5br
6br
七,
期望输出:
<p>1<br>2</p>
<p>3<br>4</p>
<p>5<br>6<br>7</p>
1
2
3
4
5
6
7
是什么原因导致
被转义,但允许转义?您是否在移除转义后尝试过?因为下面的方法对我有用吗
@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\r\n', u'<br/>') for p in _paragraph_re.split(value))
if eval_ctx.autoescape:
result = Markup(result)
return result
给我下面的输出
<p>1<br/>2</p>
<p>3<br/>4</p>
<p>5<br/>6<br/>7</p>
1
2
3
4
5
6
7
nl2br
筛选器无法正确处理标记对象。如果value
是标记,则插入的
标记将被转义。要修复它,
标记也必须是标记:
@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', Markup('<br>\n'))
for p in _paragraph_re.split(value))
if eval_ctx.autoescape:
result = Markup(result)
return result
根据:
标记字符串上的操作是标记感知的,这意味着所有参数都通过escape()函数传递
回顾nl2br
的主要转换,我们可以看到发生了什么以及为什么它不起作用:
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', u'<br>\n')
for p in _paragraph_re.split(value))
result=u'\n\n.加入(u'%s'%p.replace(u'\n',u'
\n'))
对于段落中的p,关于拆分(值))
u'\n\n'
和u'
\n'
是unicode字符串,但p
是Markup
已从作为标记对象的值中拆分出来p.replace
尝试将unicode字符串添加到标记对象p
,但标记对象首先正确截取并转义该字符串
标记不会转义,因为Python是如何组合最终字符串的,因为对unicode字符串调用了%
格式化方法,所以它使用传递给它的元素的unicode表示形式。标记元素已经被声明为安全的,因此它们不再被转义<代码>结果
以unicode字符串结束。在我写这篇文章时,这里的其他两个答案不会转义
标记,但它们容易受到XSS攻击。使用以下输入字符串进行测试:
';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--
></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
您认为转义是不必要的,这是对的,但是如果传入的值是标记对象,那么转义就不起作用。标记文字是unicode字符串,不受标记转义函数的约束。我认为这容易受到XSS的攻击。我通过注入
”来测试它;警报(String.fromCharCode(88,83,83))/';警报(String.fromCharCode(88,83,83))/“警报(String.fromCharCode(88,83,83))/”;alert(String.fromCharCode(88,83,83))/->“>”>alert(String.fromCharCode(88,83,83))
我认为这容易受到XSS的攻击。我通过注入';alert(String.fromCharCode(88,83,83))/';alert(String.fromCharCode(88,83,83))对其进行了测试//"; 警报(String.fromCharCode(88,83,83))/“;alert(String.fromCharCode(88,83,83))/-->“>”>alert(String.fromCharCode(88,83,83))
-1;正如@DavidXia所指出的,如果你做{{一些用户提供的数据{nl2br}
,这会造成一个巨大的XSS漏洞。你不需要做任何像他在评论中显示的那样复杂的事情;我只是试着做{{alert(1)}nl2br}
在一个模板中,当我刷新页面时,我确实看到了一个警报。这真的非常令人伤心,因为他改编的内容实际上是正确的。值得一提的是,演示其他两个答案中的XSS漏洞并不需要像您在这里测试的那样复杂的测试字符串。其他两个答案最终都是正确的t将值
格式化为普通字符串,然后将其传递给标记()
构造函数(因此错误),而不进行任何转义。警报('pwned')
足以表明它们已损坏。请注意,虽然这修复了逃逸的错误,但将正则表达式从OP的调整版本更改回文档片段的原始版本会在处理文档中版本的Windows样式新行时重新引入错误。有关更多说明,请参阅。此文件的正常工作版本ter应将'
\n'
字符串包装在标记()
中,如图所示,并另外使用问题中所示的固定正则表达式,并在Alan Moore的回答中解释。
>>> Markup("hello there").split()
[Markup(u'hello'), Markup(u'there')]
result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', u'<br>\n')
for p in _paragraph_re.split(value))
';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--
></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
import re
from jinja2 import evalcontextfilter, Markup, escape
_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
app = Flask(__name__)
@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n') \
for p in _paragraph_re.split(escape(value)))
if eval_ctx.autoescape:
result = Markup(result)
return result
result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', Markup('<br/>\n')) \
for p in _paragraph_re.split(escape(value)))