Python Web Flask源码解读!模板渲染过程!

从文件读取到SSTI:Web安全漏洞链实战解析 在Web安全领域,文件读取漏洞(LFI)和服务器端模板注入(SSTI)是两类常见的安全威胁。文件读取漏洞通常源于对用户输入路径的校验不足,攻击者可利用file://协议或路径遍历读取服务器敏感文件,如配置文件或源代码。SSTI则发生在用户输入被直接拼接进模板引擎渲染时,攻击者通过注入模板语法实现远程代码执行。这两类漏洞的技术价值在于,它们常被组合利用形成攻击链:攻击者先通过文件读取获取应用源码,分析出框架类型和模板引擎,再针对性地构造SSTI载荷。这种组合攻击在CTF竞赛和真实渗透测试中极为典型,尤其适用于 阅读详情

关于我

编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。

Github: github.com/hylinux1024

微信公众号:angrycode

Python资源共享群:484031800

前面对 Flask 启动流程 和路由原理都进行了源码走读。今天我们看看 模板渲染 的过程。

0x00 使用模板

首先看一个来自官方文档使用模板渲染的例子

from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)
复制代码

在项目目录下需要有一个 templates 目录,并创建了一个 hello.html 文件

/templates
    /hello.html
复制代码

hello.html 的内容为

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}
复制代码

这个模板中 name 是参数,通过调用 render_template 方法就可以根据参数实现 html 模板文件的渲染。

0x01 Flask.render_template

def render_template(template_name, **context):
    """Renders a template from the template folder with the given
    context.
    :param template_name: the name of the template to be rendered
    :param context: the variables that should be available in the
                    context of the template.
    """
    current_app.update_template_context(context)
    return current_app.jinja_env.get_template(template_name).render(context)
复制代码

方法的注释很清楚,从 templates 文件夹中找到名称为 template_name 的文件进行渲染。其中 current_app 是通过以下语句初始化

_request_ctx_stack = LocalStack()
current_app = LocalProxy(lambda: _request_ctx_stack.top.app)
复制代码

LocalStack 就是一个 栈的实现类 。而 _request_ctx_stack 是在 Flask.request_context() 方法中将当前的上下文实例 push 到栈里面的

def request_context(self, environ):
    """Creates a request context from the given environment and binds
    it to the current context.  This must be used in combination with
    the `with` statement because the request is only bound to the
    current context for the duration of the `with` block.
    Example usage::
        with app.request_context(environ):
            do_something_with(request)
    :params environ: a WSGI environment
    """
    return _RequestContext(self, environ)
复制代码

_RequestContext 类实现了上下文管理器协议,它可以在 with 语句中使用

class _RequestContext(object):
    """The request context contains all request relevant information.  It is
    created at the beginning of the request and pushed to the
    `_request_ctx_stack` and removed at the end of it.  It will create the
    URL adapter and request object for the WSGI environment provided.
    """
    def __init__(self, app, environ):
        self.app = app
        self.url_adapter = app.url_map.bind_to_environ(environ)
        self.request = app.request_class(environ)
        self.session = app.open_session(self.request)
        self.g = _RequestGlobals()
        self.flashes = None
    def __enter__(self):
        _request_ctx_stack.push(self)
    def __exit__(self, exc_type, exc_value, tb):
        # do not pop the request stack if we are in debug mode and an
        # exception happened.  This will allow the debugger to still
        # access the request object in the interactive shell.
        if tb is None or not self.app.debug:
            _request_ctx_stack.pop()
复制代码

执行 __enter__() 时操作 push ,退出 with 语句时就执行 pop 操作。

回到 request_context() 方法,它是在 wsgi_app() 中被调用的

def wsgi_app(self, environ, start_response):
    """The actual WSGI application.  This is not implemented in
    `__call__` so that middlewares can be applied:
        app.wsgi_app = MyMiddleware(app.wsgi_app)
    :param environ: a WSGI environment
    :param start_response: a callable accepting a status code,
                           a list of headers and an optional
                           exception context to start the response
    """
    with self.request_context(environ):
        rv = self.preprocess_request()
        if rv is None:
            rv = self.dispatch_request()
        response = self.make_response(rv)
        response = self.process_response(response)
        return response(environ, start_response)
复制代码

从路由原理文章的分析知道, wsgi_app() 在服务端接收到客户端请求时就会执行。 所以当请求来临时,就会把当前 Flask 实例的请求上下文实例保存到栈实例 _request_ctx_stack 中;请求处理后,就从栈里面弹出当前请求的上下文实例。

LocalProxy 是一个代理类,它的构造函数传递了一个 lambda 表达式: lambda: _request_ctx_stack.top.app 。 这个操作就把当前的上下文实例通过 LocalProxy 进行了封装,即 current_app 是当前 Flask 实例的上下文的代理。 所以当 current_app.jinja_env 这个语句其实就是访问 Flask 的实例属性 jinja_env ,这个属性是在 Flask 的构造函数中进行初始化的。

class Flask(object):
    ...
    #: 源码太长了省略
    #: options that are passed directly to the Jinja2 environment
    jinja_options = dict(
        autoescape=True,
        extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
    )
    def __init__(self, package_name):
        ...
        #: 源码太长省略部分源码
        #: the Jinja2 environment.  It is created from the
        #: :attr:`jinja_options` and the loader that is returned
        #: by the :meth:`create_jinja_loader` function.
        self.jinja_env = Environment(loader=self.create_jinja_loader(),
                                     **self.jinja_options)
        self.jinja_env.globals.update(
            url_for=url_for,
            get_flashed_messages=get_flashed_messages
        )
复制代码

jinja_env 是一个 Environment 实例。 这个是 jinja 模板引擎提供的类, Flask 框架的模板渲染就是通过 jinja 来实现的。 Environment 需要一个 loader ,是通过以下方法获取的

def create_jinja_loader(self):
    """Creates the Jinja loader.  By default just a package loader for
    the configured package is returned that looks up templates in the
    `templates` folder.  To add other loaders it's possible to
    override this method.
    """
    if pkg_resources is None:
        return FileSystemLoader(os.path.join(self.root_path, 'templates'))
    return PackageLoader(self.package_name)
复制代码

默认情况下是从 templates 目录下构造一个 FileSystemLoader 的实例,这个类的作用就是从文件系统中加载模板文件的。

0x02 Environment.get_template

@internalcode
def get_template(self, name, parent=None, globals=None):
    """Load a template from the loader.  If a loader is configured this
    method ask the loader for the template and returns a :class:`Template`.
    If the `parent` parameter is not `None`, :meth:`join_path` is called
    to get the real template name before loading.
    The `globals` parameter can be used to provide template wide globals.
    These variables are available in the context at render time.
    If the template does not exist a :exc:`TemplateNotFound` exception is
    raised.
    .. versionchanged:: 2.4
       If `name` is a :class:`Template` object it is returned from the
       function unchanged.
    """
    if isinstance(name, Template):
        return name
    if parent is not None:
        name = self.join_path(name, parent)
    return self._load_template(name, self.make_globals(globals))
复制代码

get_template() 方法内部调用了 _load_template() 方法

@internalcode
def _load_template(self, name, globals):
    if self.loader is None:
        raise TypeError('no loader for this environment specified')
    if self.cache is not None:
        template = self.cache.get(name)
        if template is not None and (not self.auto_reload or \
                                     template.is_up_to_date):
            return template
    template = self.loader.load(self, name, globals)
    if self.cache is not None:
        self.cache[name] = template
    return template
复制代码

_load_template() 方法首先会检查是否有缓存,如果缓存可用就使用缓存;缓存不可用就使用 loader 加载模板,这个 loader 就是前面提到的 FileSystemLoader 的实例(默认情况下)。

0x03 BaseLoader.load

@internalcode
def load(self, environment, name, globals=None):
    ...
    # 省略部分源码
    return environment.template_class.from_code(environment, code, globals, uptodate)
复制代码

BaseLoader 是 FileSystemLoader 的基类。这个 load 方法实现了模板的编译、加载等逻辑。最后是使用 environment.template_class.from_code() 方法。其中 template_class 是 Template 类,它代表编译后的模板对象。 from_code 是 Template 类的静态方法,可以用来创建一个 Template 实例。当 load 方法返回时,就得到了一个 Template 对象。 最后回到 render_template 方法

def render_template(template_name, **context):
    ...
    return current_app.jinja_env.get_template(template_name).render(context)
复制代码

执行了 Template 对象的 render() 方法。

0x04 Template.render

def render(self, *args, **kwargs):
    """This function accepts either a dict or some keyword arguments which
    will then be the context the template is evaluated in.  The return
    value will be the rendered template.
    :param context: the function accepts the same arguments as the
                    :class:`dict` constructor.
    :return: the rendered template as string
    """
    ns = self.default_context.copy()
    if len(args) == 1 and isinstance(args[0], utils.MultiDict):
        ns.update(args[0].to_dict(flat=True))
    else:
        ns.update(dict(*args))
    if kwargs:
        ns.update(kwargs)
    context = Context(ns, self.charset, self.errors)
    exec self.code in context.runtime, context
    return context.get_value(self.unicode_mode)
复制代码

这个方法接收一个 dict 类型参数,用于给模板传递参数。该方法的**核心是执行 exec **函数。 exec 是 Python 内置函数,它可以动态的执行 Python 代码。

0x05 总结一下

Flask 使用 Jinja 作为模板引擎。执行路径为

Flask.render_template => Environment.get_template => Template.render => exec
复制代码
全面解读Web开发框架:原理、实现与应用 Express.js是一种灵活的Node.js Web应用框架,提供了一系列强大的特性,用于开发各种Web和移动应用。在Express中,中间件是构成应用的主要构件,它们是能够访问请求对象(req)、响应对象(res)以及应用程序中处于请求-响应循环流程中的下一个中间件函数的函数。Express中间件工作流程:当一个HTTP请求到达Express应用时,它开始进入一个中间件函数栈。中间件函数可以执行各种任务,比如解析请求体、添加响应头、或者记录日志。 阅读详情

相关推荐

Flask+MySQL电商项目源码全解析:从解压到跑通核心代码

Web应用开发中,后端框架与数据库的协作决定了项目的稳定性和可维护性。Flask作为轻量级Python框架,凭借灵活性和高透明度,成为理解Web请求-响应循环的绝佳选择;MySQL则以其关系型存储和事务支持,保障了电商场景下数据的一致性与完整性。二者结合,常被用于搭建具备用户、商品、购物车、订单等核心模块的电商系统。对于刚学完Python基础、或正在准备课程设计与毕业设计的开发者而言,通过阅读一套完整源码,理清环境配置、SQL初始化、业务模块拆分与部署排错,是快速掌握全栈开发思维、积累项目经验的有效路径。本

weixin_32821533的博客 330

python flask源码解析_flask 源码解析:简介

这是 flask 源码解析系列文章的其中一篇,本系列所有文章列表:flask 简介Flask 官网上对它的定位是一个“微” python web 开发框架。Flask is a micro web development framework for Python.python 语言 web 框架很多:Django、Tornado、webpy、bottle……,flask 的特点是简单可扩展。简单有...

weixin_26840895的博客 763

python基于flask的管理系统源码.zip

python基于flask的管理系统源码.zip

Flask源码剖析(1)

文章目录1 预备知识1.1 setattr、getattr、delattr1.2 python新式类的超能力1.3 实例初始化中的递归问题1.4 偏函数1.5 代理设计模式1.6 本地线程2 开始剖析flask2.1 创建一个最小的flask应用(1)(2)(3)请求进来执行app() 也就是Flask的call方法(4)wagi_app接受了请求参数组成的字段和可调用的响应2.2 使用请求参数(1) from flask import request(2) 请求参数被存储后的使用流程2.3 LocalP

kobe_okok的博客 1089

STC15W204S最小系统开发指南:从串口通讯到自动热加载全流程

本文详细介绍了STC15W204S最小系统的完整开发流程。从芯片资源解析、最小系统搭建、串口通讯驱动编写(使用Timer2生成波特率),到实现基于魔术值触发的自动热加载功能,并最终集成Keil与STC-ISP软件,构建高效的自动化开发工作流,显著提升嵌入式调试效率。

a1b2c的博客 391

从大疆智图到Cesium:3D Tiles模型加载与Web三维场景构建实战

本文详细介绍了如何利用大疆智图生成3D Tiles数据,并通过Cesium在Web端实现高效加载与三维场景构建。从大疆智图参数设置到Cesium环境配置,再到3D Tiles性能调优与高级功能实现,提供了一套完整的实战指南,帮助开发者快速掌握3D Tiles模型加载与Web三维场景构建技术。

weixin_30520015的博客 1285

复盘Flask-web网页开发——模板渲染

jinja2 是 Flask 作者开发的一个模板系统,起初是仿 Django 模板的一个模板引擎,为 Flask 提供模板支持,由于其灵活,快速和安全等优点被广泛使用。当我们开发 Web 应用程序时,通常需要将数据动态地渲染到 HTML 模板中,而 Python jinja2 模版技术正是为此而生的。模板在 Python 的web开发中广泛使用,它能够有效的将业务逻辑和页面逻辑分开,使代码可读性增强、并且更加容易理解和维护。部分的文件,模板文件在经过动态赋值后,返回给用户。模板简单来说就是一个其中包含。

m0_66151412的博客 398

MQTT在智能家居中的实战:用Android手机控制ESP8266设备(基于EMQX)

本文详细介绍了如何利用MQTT协议构建一个完整的智能家居控制系统,通过Android手机App远程操控ESP8266设备。文章提供了从EMQX服务器部署、ESP8266端Arduino固件开发到Android客户端搭建的完整实战指南,并深入探讨了系统联调、稳定性优化与安全加固等关键环节,为物联网开发者提供了一套可复用的解决方案。

ujm567890的博客 457

python flask源码_Flask 源码阅读笔记 开篇

Flask 是一个 Python 实现的 Web 开发微框架, 有丰富的生态资源。本文从一段官方的示例代码通过一步步打断点方式解释 Flask 内部的运行机制,在一些关键概念会有相关解释,这些前提概念对整体理解 Flask框架十分重要,本文基于flask 0.1 版本进行相应的分析。官方demo示例from flask import Flaskapp = Flask(__name__)@app.r...

weixin_39646658的博客 193

R语言实战:非正态数据下的Scheirer–Ray–Hare检验全流程解析

本文详细解析了在R语言中执行Scheirer–Ray–Hare检验的全流程。当数据不满足正态分布假设时,该非参数检验是传统双因素方差分析的有效替代方案。文章从原理、R环境配置、数据准备、代码实现、结果解读到事后比较与可视化,提供了完整的实战指南,帮助研究者稳健地分析多因素实验设计中的主效应和交互效应。

cc789的博客 406

大语言模型的三种主要架构 Decoder-Only、Encoder-Only、Encoder-Decoder

f基于 Transformer 模型以非灰色显示:decoder-only 模型在蓝色分支,encoder-only 模型在粉色分支,encoder-decoder 模型在绿色分支。模型在时间线上的垂直位置表示它们的发布日期。开源模型由实心方块表示,而闭源模型由空心方块表示。右下角的堆积条形图显示了各公司和机构的模型数量。从时间轴上,我们可以看到:2021年前,当 OpenAI 决定在,他们实际上是在逆流而上。

u010899985的博客 2万+

flask源码

这只是Flask源码的一个简单概览,实际上,Flask源码还包含了许多其他文件和模块,用于处理会话、模板引擎、静态文件管理等功能。Flask的源码设计简洁而灵活,提供了很多扩展点,使得开发者可以根据自己的需求进行定制和扩展。如果你对Flask的具体实现细节和设计思想感兴趣,建议你阅读Flask源码并进行深入研究。

2302_77595648的博客 1183

《QGIS快速入门与应用基础》010:下载过程中常见问题(如网速慢、文件损坏)

针对QGIS下载过程中的常见问题提供了系统解决方案。主要解决下载速度慢(≤100KB/s)和文件损坏两大核心问题:通过切换国内镜像源(如清华大学、阿里云)、使用专业下载工具提升速度;采用MD5/SHA256校验确保文件完整性,并排查存储介质和杀毒软件干扰。文章还包含macOS权限问题、Linux依赖缺失等高频问题的速解方案,并附详细的排查流程图和预防技巧,帮助用户顺利完成QGIS下载。后续将详细介绍安装流程,适合零基础用户参考。

LuckyHanMo的博客 482

python web 模版_Python Web Flask源码解读!模板渲染过程!

关于我编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。微信公众号:angrycodePython资源共享群:484031800前面对 Flask 启动流程 和路由原理都进行了源码走读。今天我们看看 模板渲染 的过程。0x00 使用模板首先看一个来自官方文档使用模板渲染的例子from flask...

weixin_39637589的博客 245

Allegro16.6详细教程(二)

3-D Viewer,可以直接在allegro中看到board file的3-D顯示效果。3-D Viewer對於PCB Editor Products,只有環境變數中的OpenGL顯示功能開啟後才有效,而對於APD/SiP是無效的。2.3-D viewer是在一個獨立的視窗中打開的。3-D environment環境支援多種顯示內容的過濾,取景視角和顯示效果的選項,透過遊標可以直接控制放大,移動,翻轉等操作。

axingxiansen的博客 1917

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Python Web Flask源码解读(三)——模板渲染过程

关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 Github:https://github.com/hylinux1024 微信公众号:终身开发者(angrycode) 前面对Flask启动流程和路由原理都进行了源码走读。今天我们看看模板渲染的过程。 0x00 ...

weixin_30364147的博客 274

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

python模板过程_Python Web Flask源码解读(三)——模板渲染过程

关于我一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。Github:https://github.com/hylinux1024微信公众号:终身开发者(angrycode)前面对Flask启动流程和路由原理都进行了源码走读。今天我们看看模板渲染的过程。0x00 使用模板首先看一个来自官...

weixin_39674028的博客 258

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Flask初版架构源码解读 | Python基础

WSGI是什么? WSGI即Web Server Gateway Interface 是基于现存的CGI标准而设计的,是Python对CGI进行的一种包装 也是一个规范,定义了Web服务器如何与Python应用程序进行交互,使得使用Python写的Web应用程序可以和Web服务器对接起来 目前Django、Flask等主流Python Web框架都实现了WSGI WSGI Web架构 对于一个遵守WSGI协议的服务器和Web应用来说, 它并不在意到底是谁传过来的数据, 只需要知道传过来

731

5分钟搞懂Flask框架设计哲学:新手必学的Python Web开发指南

Flask是一个轻量级Python Web框架,以"微框架"设计理念著称,允许开发者按需扩展功能,快速构建Web应用和API。本文将深入解析Flask的核心设计哲学与技术决策,帮助新手理解其为何成为Python Web开发的首选框架之一。 ## 🔥 Flask的"微而不简"设计哲学 Flask遵循"微框架"设计理念,核心仅包含Web开发的必要组件:路由系统、模板引擎和请求处理。这种设计让开发

gitblog_00023的博客 412

Flask源码剖析(来自:赖明星 《Python Linux系统管理与自动化运维》作者)

1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识。从而,在使用flask过程中,能够减少困惑,胸有成竹,遇bug而不惊。 在试图理解flask的设计之前,你知道应该知道以下几个概念: flask(web框架)是什么 WSGI是什么 j...

h18208975507的博客 209

Falsk源码分析

1、简单解析可参考: flask 源码解析:简介 | Cizixs Write Here 2、总结流程:

阿茂丶 349

Python Flask实时数据可视化系统搭建实战

实时数据可视化是IoT监控、运营看板等场景的核心能力,其本质在于构建一条稳定高效的数据链路:从设备端数据产生,经传输与内存聚合处理,最终在前端图表中低延迟渲染。Flask凭借轻量灵活、调试直观和模板友好等优势,成为中小规模实时看板的理想后端框架;Ajax轮询在≤10Hz更新频率下,相比WebSocket具备更优的兼容性、可维护性与故障定位效率。结合Docker容器化封装,可实现一键部署、环境一致与快速回滚,显著降低交付门槛。本文基于真实仓储WMS看板项目,详解如何用Python+Flask+Ajax+Doc

weixin_30696427的博客 392

Flask源码剖析详解

1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识。从而,在使用flask过程中,能够减少困惑,胸有成竹,遇bug而不惊。 在试图理解flask的设计之前,你知道应该知道以下几个概念: flask(web框架)是什么 WSGI是...

weixin_30263277的博客 107
上一篇: 如何在 Python 中用中文做数学运算?
下一篇: Python基础 ,快速实现命令行参数解析!
普通网友
博客等级 码龄7年 438粉丝 263原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值