• html自动转意
    • 如何关闭它
      • 对于单独的变量
      • 对于模板块
    • 备注
    • 过滤器参数里的字符串常量的自动转义

    html自动转意

    从模板生成html的时候,总是有一个风险——变量包了含会影响结果html的字符。 例如,考虑这个模板片段:

    1. Hello, {{ name }}.

    一开始,这看起来是显示用户名的一个无害的途径,但是考虑如果用户输入如下的名字将会发生什么:

    1. <script>alert('hello')</script>

    用这个用户名,模板将被渲染成:

    1. Hello, <script>alert('hello')</script>

    这意味着浏览器将弹出JavaScript警告框!

    类似的,如果用户名包含小于符号,就像这样:

    用户名

    那样的话模板结果被翻译成这样:

    1. Hello, <b>username

    页面的剩余部分变成了粗体!

    显然,用户提交的数据不应该被盲目信任,直接插入到你的页面中。因为一个潜在的恶意的用户能够利用这类漏洞做坏事。 这类漏洞称为被跨域脚本 (XSS) 攻击。 关于安全的更多内容,请看20章

    为了避免这个问题,你有两个选择:

    • 一是你可以确保每一个不被信任的变量都被escape过滤器处理一遍,把潜在有害的html字符转换为无害的。 这是最初几年Django的默认方案,但是这样做的问题是它把责任推给(开发者、模版作者)自己,来确保把所有东西转意。 很容易就忘记转意数据。

    • 二是,你可以利用Django的自动html转意。 这一章的剩余部分描述自动转意是如何工作的。

    在django里默认情况下,每一个模板自动转意每一个变量标签的输出。 尤其是这五个字符。

    • ```\ ```

    System Message: WARNING/2 (&lt;string&gt;, line 491); backlink

    Inline literal start-string without end-string.

    • > 被转换为>

    • '(单引号)被转换为'

    • "(双引号)被转换为"

    • & is converted to &

    另外,我强调一下这个行为默认是开启的。 如果你正在使用django的模板系统,那么你是被保护的。

    如何关闭它

    如果你不想数据被自动转意,在每一站点级别、每一模板级别或者每一变量级别你都有几种方法来关闭它。

    为什么要关闭它? 因为有时候模板变量包含了一些原始html数据,在这种情况下我们不想它们的内容被转意。 例如,你可能在数据库里存储了一段被信任的html代码,并且你想直接把它嵌入到你的模板里。 或者,你可能正在使用Django的模板系统生成非html文本,比如一封e-mail。

    对于单独的变量

    用safe过滤器为单独的变量关闭自动转意:

    1. This will be escaped: {{ data }}
    2. This will not be escaped: {{ data|safe }}

    你可以把safe当做safe from further escaping的简写,或者当做可以被直接译成HTML的内容。在这个例子里,如果数据包含'',那么输出会变成:

    1. This will be escaped: &lt;b&gt;
    2. This will not be escaped: <b>

    对于模板块

    为了控制模板的自动转意,用标签autoescape来包装整个模板(或者模板中常用的部分),就像这样:

    1. {% autoescape off %}
    2. Hello {{ name }}
    3. {% endautoescape %}

    autoescape 标签有两个参数on和off 有时,你可能想阻止一部分自动转意,对另一部分自动转意。 这是一个模板的例子:

    1. Auto-escaping is on by default. Hello {{ name }}
    2. {% autoescape off %}
    3. This will not be auto-escaped: {{ data }}.
    4. Nor this: {{ other_data }}
    5. {% autoescape on %}
    6. Auto-escaping applies again: {{ name }}
    7. {% endautoescape %}
    8. {% endautoescape %}

    auto-escaping 标签的作用域不仅可以影响到当前模板还可以通过include标签作用到其他标签,就像block标签一样。 例如:

    1. # base.html
    2. {% autoescape off %}
    3. <h1>{% block title %}{% endblock %}</h1>
    4. {% block content %}
    5. {% endblock %}
    6. {% endautoescape %}
    7. # child.html
    8. {% extends "base.html" %}
    9. {% block title %}This & that{% endblock %}
    10. {% block content %}{{ greeting }}{% endblock %}

    由于在base模板中自动转意被关闭,所以在child模板中自动转意也会关闭.因此,在下面一段HTML被提交时,变量greeting的值就为字符串Hello!

    1. <h1>This & that</h1>
    2. <b>Hello!</b>

    备注

    通常,模板作者没必要为自动转意担心. 基于Pyhton的开发者(编写VIEWS视图和自定义过滤器)只需要考虑哪些数据不需要被转意,适时的标记数据,就可以让它们在模板中工作。

    如果你正在编写一个模板而不知道是否要关闭自动转意,那就为所有需要转意的变量添加一个escape过滤器。 当自动转意开启时,使用escape过滤器似乎会两次转意数据,但其实没有任何危险。因为escape过滤器不作用于被转意过的变量。

    过滤器参数里的字符串常量的自动转义

    就像我们前面提到的,过滤器也可以是字符串.

    1. {{ data|default:"This is a string literal." }}

    所有字符常量没有经过转义就被插入模板,就如同它们都经过了safe过滤。 这是由于字符常量完全由模板作者决定,因此编写模板的时候他们会确保文本的正确性。

    这意味着你必须这样写

    1. {{ data|default:"3 &lt; 2" }}

    而不是这样

    1. {{ data|default:"3 < 2" }} <-- Bad! Don't do this.

    这点对来自变量本身的数据不起作用。 如果必要,变量内容会自动转义,因为它们不在模板作者的控制下。