国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

讓我們一起來構(gòu)建一個(gè)模板引擎(四)

yuxue / 2559人閱讀

摘要:在本文中我們將解決一些用于生成的模板引擎需要面對(duì)的一些安全問題。整個(gè)系列的所有文章地址讓我們一起來構(gòu)建一個(gè)模板引擎一讓我們一起來構(gòu)建一個(gè)模板引擎二讓我們一起來構(gòu)建一個(gè)模板引擎三讓我們一起來構(gòu)建一個(gè)模板引擎四文章中涉及的代碼已經(jīng)放到上了

在 上篇文章 中我們的模板引擎實(shí)現(xiàn)了對(duì) includeextends 的支持, 到此為止我們已經(jīng)實(shí)現(xiàn)了模板引擎所需的大部分功能。 在本文中我們將解決一些用于生成 html 的模板引擎需要面對(duì)的一些安全問題。

轉(zhuǎn)義

首先要解決的就是轉(zhuǎn)義問題。到目前為止我們的模板引擎并沒有對(duì)變量和表達(dá)式結(jié)果進(jìn)行轉(zhuǎn)義處理, 如果用于生成 html 源碼的話就會(huì)出現(xiàn)下面這樣的問題 ( template3c.py ):

>>> from template3c import Template
>>> t = Template("

{{ title }}

") >>> t.render({"title": "hello
world"}) "

hello
world

"

很明顯 title 中包含的標(biāo)簽需要被轉(zhuǎn)義,不然就會(huì)出現(xiàn)非預(yù)期的結(jié)果。 這里我們只對(duì) & " " > < 這幾個(gè)字符做轉(zhuǎn)義處理,其他的字符可根據(jù)需要進(jìn)行處理。

html_escape_table = {
    "&": "&",
    """: """,
    """: "'",
    ">": ">",
    "<": "<",
}


def html_escape(text):
    return "".join(html_escape_table.get(c, c) for c in text)

轉(zhuǎn)義效果:

>>> html_escape("hello
world") "hello
world"

既然有轉(zhuǎn)義自然也要有禁止轉(zhuǎn)義的功能,畢竟不能一刀切否則就喪失靈活性了。

class NoEscape:

    def __init__(self, raw_text):
        self.raw_text = raw_text


def escape(text):
    if isinstance(text, NoEscape):
        return str(text.raw_text)
    else:
        text = str(text)
        return html_escape(text)


def noescape(text):
    return NoEscape(text)

最終我們的模板引擎針對(duì)轉(zhuǎn)義所做的修改如下(可以下載 template4a.py ):

class Template:
    def __init__(self, ..., auto_escape=True):
        ...
        self.auto_escape = auto_escape
        self.default_context.setdefault("escape", escape)
        self.default_context.setdefault("noescape", noescape)
        ...

    def _handle_variable(self, token):
        if self.auto_escape:
            self.buffered.append("escape({})".format(variable))
        else:
            self.buffered.append("str({})".format(variable))

    def _parse_another_template_file(self, filename):
        ...
        template = self.__class__(
                ...,
                auto_escape=self.auto_escape
        )
        ...


class NoEscape:
    def __init__(self, raw_text):
        self.raw_text = raw_text

html_escape_table = {
    "&": "&",
    """: """,
    """: "'",
    ">": ">",
    "<": "<",
}


def html_escape(text):
    return "".join(html_escape_table.get(c, c) for c in text)


def escape(text):
    if isinstance(text, NoEscape):
        return str(text.raw_text)
    else:
        text = str(text)
        return html_escape(text)


def noescape(text):
    return NoEscape(text)

效果:

>>> from template4a import Template
>>> t = Template("

{{ title }}

") >>> t.render({"title": "hello
world"}) "

hello
world

" >>> t = Template("

{{ noescape(title) }}

") >>> t.render({"title": "hello
world"}) "

hello
world

" >>>
exec 的安全問題

由于我們的模板引擎是使用 exec 函數(shù)來執(zhí)行生成的代碼的,所有就需要注意一下 exec 函數(shù)的安全問題,預(yù)防可能的服務(wù)端模板注入攻擊(詳見 使用 exec 函數(shù)時(shí)需要注意的一些安全問題 )。

首先要限制的是在模板中使用內(nèi)置函數(shù)和執(zhí)行時(shí)上下文變量( template4b.py ):

class Template:
    ...

    def render(self, context=None):
        """渲染模版"""
        namespace = {}
        namespace.update(self.default_context)
        namespace.setdefault("__builtins__", {})   # <---
        if context:
            namespace.update(context)
        exec(str(self.code_builder), namespace)
        result = namespace[self.func_name]()
        return result

效果:

>>> from template4b import Template
>>> t = Template("{{ open("/etc/passwd").read() }}")
>>> t.render()
Traceback (most recent call last):
  File "", line 1, in 
  File "/Users/mg/develop/lsbate/part4/template4b.py", line 245, in render
    result = namespace[self.func_name]()
  File "", line 3, in __func_name
NameError: name "open" is not defined

然后就是要限制通過其他方式調(diào)用內(nèi)置函數(shù)的行為:

>>> from template4b import Template
>>> t = Template("{{ escape.__globals__["__builtins__"]["open"]("/etc/passwd").read()[0] }}")
>>> t.render()
"#"
>>>
>>> t = Template("{{ [x for x in [].__class__.__base__.__subclasses__() if x.__name__ == "_wrap_close"][0].__init__.__globals__["path"].os.system("date") }}")
>>> t.render()
Mon May 30 22:10:46 CST 2016
"0"

一種解決辦法就是不允許在模板中訪問以下劃線 _ 開頭的屬性。 為什么要包括單下劃線呢,因?yàn)榧s定單下劃線開頭的屬性是約定的私有屬性, 不應(yīng)該在外部訪問這些屬性。

這里我們使用 dis 模塊來幫助我們解析生成的代碼,然后再找出其中的特殊屬性
這里我們使用 tokenize 模塊來幫助我們解析生成的代碼,然后再找出其中的特殊屬性。

    import io
    import tokenize


    class Template:
        def __init__(self, ..., safe_attribute=True):
            ...
            self.safe_attribute = safe_attribute

        def render(self, ...):
            ...
            code = str(self.code_builder)
            if self.safe_attribute:
                check_unsafe_attributes(code)
            exec(code, namespace)
            func = namespace[self.func_name]

    def check_unsafe_attributes(s):
        g = tokenize.tokenize(io.BytesIO(s.encode("utf-8")).readline)
        pre_op = ""
        for toktype, tokval, _, _, _ in g:
            if toktype == tokenize.NAME and pre_op == "." and 
                    tokval.startswith("_"):
                attr = tokval
                msg = "access to attribute "{0}" is unsafe.".format(attr)
                raise AttributeError(msg)
            elif toktype == tokenize.OP:
                pre_op = tokval

效果:

>>> from template4c import Template
>>> t = Template("{{ [x for x in [].__class__.__base__.__subclasses__() if x.__name__ == "_wrap_close"][0].__init__.__globals__["path"].os.system("date") }}")
>>> t.render()
Traceback (most recent call last):
  File "", line 1, in 
  File "/xxx/lsbate/part4/template4c.py", line 250, in render
    check_unsafe_attributes(func)
  File "/xxx/lsbate/part4/template4c.py", line 296, in check_unsafe_attributes
    raise AttributeError(msg)
AttributeError: access to attribute "__class__" is unsafe.
>>>
>>> t = Template("

{{ title }}

") >>> t.render({"title": "hello
world"}) "

hello
world

"

這個(gè)系列的文章到目前為止就已經(jīng)全部完成了。

如果大家感興趣的話可以嘗試使用另外的方式來解析模板內(nèi)容, 即: 使用詞法分析/語(yǔ)法分析的方式來解析模板內(nèi)容(歡迎分享實(shí)現(xiàn)過程)。

P.S. 整個(gè)系列的所有文章地址:

讓我們一起來構(gòu)建一個(gè)模板引擎(一)

讓我們一起來構(gòu)建一個(gè)模板引擎(二)

讓我們一起來構(gòu)建一個(gè)模板引擎(三)

讓我們一起來構(gòu)建一個(gè)模板引擎(四)

P.S. 文章中涉及的代碼已經(jīng)放到 GitHub 上了: https://github.com/mozillazg/lsbate

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/45470.html

相關(guān)文章

  • 我們起來構(gòu)建個(gè)模板引擎(三)

    摘要:在上篇文章中我們的模板引擎實(shí)現(xiàn)了對(duì)和對(duì)支持,同時(shí)在文章的最后我給大家留了一個(gè)問題如何實(shí)現(xiàn)支持和的標(biāo)簽功能。在本篇文章中我們將一起來動(dòng)手實(shí)現(xiàn)這兩個(gè)功能。 在 上篇文章 中我們的模板引擎實(shí)現(xiàn)了對(duì) if 和 for 對(duì)支持,同時(shí)在文章的最后我給大家留了一個(gè) 問題:如何實(shí)現(xiàn)支持 include 和 extends 的標(biāo)簽功能。 在本篇文章中我們將一起來動(dòng)手實(shí)現(xiàn)這兩個(gè)功能。 include in...

    3fuyu 評(píng)論0 收藏0
  • webpack多頁(yè)應(yīng)用架構(gòu)系列(十五):論前端如何在后端渲染開發(fā)模式下夾縫生存

    摘要:回到純靜態(tài)頁(yè)面開發(fā)階段,讓頁(yè)面不需要后端渲染也能跑起來。改造開始本文著重介紹如何將靜態(tài)頁(yè)面改造成后端渲染需要的模板。總結(jié)在后端渲染的項(xiàng)目里使用多頁(yè)應(yīng)用架構(gòu)是絕對(duì)可行的,可不要給老頑固們嚇唬得又回到傳統(tǒng)前端架構(gòu)了。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/119000000820338...

    dinfer 評(píng)論0 收藏0
  • webpack多頁(yè)應(yīng)用架構(gòu)系列(十五):論前端如何在后端渲染開發(fā)模式下夾縫生存

    摘要:回到純靜態(tài)頁(yè)面開發(fā)階段,讓頁(yè)面不需要后端渲染也能跑起來。改造開始本文著重介紹如何將靜態(tài)頁(yè)面改造成后端渲染需要的模板。總結(jié)在后端渲染的項(xiàng)目里使用多頁(yè)應(yīng)用架構(gòu)是絕對(duì)可行的,可不要給老頑固們嚇唬得又回到傳統(tǒng)前端架構(gòu)了。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/119000000820338...

    dingda 評(píng)論0 收藏0
  • 基于TmodJS的前端模板工程化解決方案

    摘要:原作者唐斌騰訊什么原名是一個(gè)簡(jiǎn)單易用的前端模板預(yù)編譯工具。本文作者為來自騰訊團(tuán)隊(duì)的唐斌,他在本文中為我們分析了傳統(tǒng)前端模板內(nèi)嵌的弊端,如開發(fā)調(diào)試效率低下自動(dòng)化構(gòu)建復(fù)雜度比較高等特點(diǎn),并針對(duì)目前現(xiàn)狀給出了較好的解決方案。 原作者: 唐斌(騰訊)| TmodJS什么 TmodJS(原名atc)是一個(gè)簡(jiǎn)單易用的前端模板預(yù)編譯工具。它通過預(yù)編譯技術(shù)讓前端模板突破瀏覽器限制,實(shí)現(xiàn)后端模板一樣的同...

    zhaochunqi 評(píng)論0 收藏0
  • 我們起來構(gòu)建個(gè)模板引擎

    摘要:使用技術(shù)我們將使用將模板編譯為代碼的方式來解析和渲染模板。下面我們就一起來實(shí)現(xiàn)這個(gè)方法。 假設(shè)我們要生成下面這樣的 html 字符串: welcome, Tom age: 20 weight: 100 height: 170 要求姓名以及 中的內(nèi)容是根據(jù)變量動(dòng)態(tài)生成的,也就是這樣的: welco...

    zombieda 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<