Django - 仅将字符串/用户输入的某些部分标记为安全?

Posted

技术标签:

【中文标题】Django - 仅将字符串/用户输入的某些部分标记为安全?【英文标题】:Django - mark only certain part of string / user input as safe? 【发布时间】:2015-01-16 10:32:00 【问题描述】:

用户文本输入如下:

Test 'post'. Post at 8:52 on Feb 3rd. /u/username created it.
This <a href="link">link</a> should not be displayed as a link.

在模板上显示用户输入时,我通过自定义过滤器发送它。这是自定义过滤器:

word_split_re = re.compile(r'(\s+)')

@register.filter
@stringfilter
def customUrlize(value):
    words = word_split_re.split(force_text(value))
    for i, b in enumerate(words):
        if b.startswith('/u/'):
            username = b[3:]
            if re.match("^[A-Za-z0-9_-]*$", username):
                b = "<a href='testLink'>" + b + "</a>"
                words[i] = mark_safe(b)
    return ''.join(words)

如您所见,我想要做的是以 '/u/' 开头的单词(并且只包含字母、数字、下划线和破折号)用

<a>

标签。使用当前过滤器,所有代码都被转义并显示为:

Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it.
This <a href="link">link</a> should not be displayed as a link.

我想要的是正常显示文本,但 /u/username 是一个链接。

如果我尝试这样做:

return mark_safe(''.join(words))

然后它甚至显示

<a href="link">link</a>

作为链接与

/u/username

如何让它只显示

/u/username

作为链接?

编辑:我使用的是 Django 1.5。

在我的模板中,假设

comment

是一个

CharField

我这样显示评论:

 comment|customUrlize 

【问题讨论】:

【参考方案1】:

除非您要保留文本中的某些其他格式,否则您可以在更改文本之前直接escape 文本。

返回带有 & 符号、引号和尖括号的给定文本,这些文本经过编码以便在 html 中使用。输入首先通过force_text(),输出应用mark_safe()

From the Django documentation

所以这一行:

words = word_split_re.split(force_text(value))

变成这样:

words = word_split_re.split(escape(value))

完整的过滤器是:

from django.utils.html import escape

word_split_re = re.compile(r'(\s+)')

@register.filter
@stringfilter
def customUrlize(value):
    words = word_split_re.split(escape(value)) 
    for i, b in enumerate(words):
        if b.startswith('/u/'):
            username = b[3:]
            if re.match("^[A-Za-z0-9_-]*$", username):
                b = "<a href='testLink'>" + b + "</a>"
                words[i] = mark_safe(b)
    return mark_safe(''.join(words))

并且应该给:

Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it.
This &lt;a href="link"&gt;link&lt;/a&gt; should not be displayed as a link.

呈现为:

测试“发布”。 2 月 3 日 8 点 52 分发帖。 /u/username 创建了它。 此链接不应显示为链接。

【讨论】:

hm,您能否再次确认您显示的呈现文本正是它为您呈现的内容?我复制粘贴了您的过滤器,但对我来说,它仍然呈现“/u/username”而不是实际链接。即使在应用了我的自定义过滤器之后,似乎 Django 也会自动转义文本。如果有帮助,我正在使用 Django 1.5。 这就是应该呈现的,我不明白这个问题。如果它没有转义 &lt; 它是否按预期工作? 渲染的文本对我来说如下所示:“测试'post'。2 月 3 日 8:52 发布。/u/username 创建了它. 此 <a href="link">link</a> 不应显示为链接。"我希望将“/u/username”呈现为实际链接,而不是在 html 中显示“”。我说的现在更有意义了吗? 另外,对不起,当我说“它仍然呈现“/u/username”时,我在最初的评论中的意思是“它仍然会呈现作为“/u/username” 远程也不行。听起来它正在显示一个链接。【参考方案2】:

根据您的需要,这可能无济于事,但您可以将字符串一分为二,并在模板中只用 |safe 标记第一个。

例如:

a = "Test 'post'. Post at 8:52 on Feb 3rd. <a href='testLink'>/u/username</a> created it. This <a href='link'>link</a> should not be displayed as a link."

b = a.split('it.')

然后将其传递给模板

'string1': b[0]
'string2': b[1]

或其他,然后在模板中string1|safe &lt;br&gt; string2

输出将如您所愿。没有“它”,当然。但这很容易解决。

【讨论】:

以上是关于Django - 仅将字符串/用户输入的某些部分标记为安全?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅将 EJB 角色授予某些实体

iOS 仅将某些推送通知过滤为徽章

反应:仅将主体类添加到 useEffect 挂钩中的某些组件?

使用递归仅将输入字符串的字母连接成单个输出字符串

如何根据用户组更改 Django 模板?

使用trim方法检测用户输入