chr*_*kso 7 python regex jinja2 flask
我正在尝试实现这个 Jinja nl2br
过滤器.它正常工作,除了<br>
它添加的它被转义.这对我来说很奇怪,因为<p>
它们没有被转义并且它们都在同一个字符串中.
我正在使用烧瓶,因此autoescape
启用了Jinja .当我发现这个人说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
Run Code Online (Sandbox Code Playgroud)
输入:
u'1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7'
Run Code Online (Sandbox Code Playgroud)
输出:
<p>1<br>
2</p>
<p>3<br>
4</p>
<p>5<br>
6<br>
7</p>
Run Code Online (Sandbox Code Playgroud)
期望的输出:
<p>1<br>2</p>
<p>3<br>4</p>
<p>5<br>6<br>7</p>
Run Code Online (Sandbox Code Playgroud)
什么可能导致<br>
逃脱,但允许<p>
的?
该nl2br
过滤器不能正确处理标记的对象.如果value
是标记,那么插入的<br>
标签将被转义.要修复它,<br>
标记也必须是标记:
@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
Run Code Online (Sandbox Code Playgroud)
注意:我将行结尾标准化为\n
.
以下是对正在发生的事情的更长解释:
拆分Markup
对象,产生许多Markup
对象:
>>> Markup("hello there").split()
[Markup(u'hello'), Markup(u'there')]
Run Code Online (Sandbox Code Playgroud)
标记字符串上的操作是标记识别的,这意味着所有参数都通过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))
Run Code Online (Sandbox Code Playgroud)
u'\n\n'
和u'<br>\n'
是Unicode字符串,但p
是Markup
已经从分裂value
,这是一个标记对象.p.replace
尝试向Markup对象添加unicode字符串p
,但Markup对象首先正确截取并转义字符串.
<p>
由于Python组装了最终字符串,因此标签不会被转义,因为%
格式化方法是在unicode字符串上调用的,它使用传递给它的元素的unicode表示.Markup元素已被声明为安全,因此它们不会被进一步转义.result
最终成为一个unicode字符串.
在我写这篇文章的时候,另外两个答案不会逃避<br/>
标签,但它们很容易受到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>
Run Code Online (Sandbox Code Playgroud)
Dan Jacob的原始nl2br jinja片段几乎就在那里:
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
Run Code Online (Sandbox Code Playgroud)
只要value
只是一个字符串,上面的代码就可以工作了.它不但不能,如果value
是已经一个Markup
对象,自那时以来,.replace()
调用导致'<br>'
串得到逃过一劫.这是从Jinja2通常处理逃逸的方式得出的; Markup
假定对象是安全的,正常的字符串对象被认为是不安全的,因此将两者结合起来的操作会自动调用正常字符串对象上的转义.
要解决这个问题,只需将其与@ joemaller创建Markup('<br/>\n')
对象的答案结合起来即可.即:
result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', Markup('<br/>\n')) \
for p in _paragraph_re.split(escape(value)))
Run Code Online (Sandbox Code Playgroud)
您是否尝试过移除逃生功能?因为下面的内容对我有用吗?
@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
Run Code Online (Sandbox Code Playgroud)
当在如下模板中使用时:
{{ '1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7' | nl2br}}
Run Code Online (Sandbox Code Playgroud)
给我下面的输出
<p>1<br/>2</p>
<p>3<br/>4</p>
<p>5<br/>6<br/>7</p>
Run Code Online (Sandbox Code Playgroud)