Jinja2模板的安全性测试与防御探究

2022-05-30 08:38石春宏
电脑知识与技术 2022年27期
关键词:安全性

摘要:Jinja2 模板的应用使得网站代码结构清晰,耦合度降低,开发、维护、更新都更容易。该文通过采用不同类型的传参对Jinja2 模板的安全性进行了测试,并在测试中发现了一些安全性问题,通过实践,给出了相应的安全防范措施,供同行人员参考。

关键词:Flask;安全性;Jinja2模板

中图分类号:TP311     文献标识码:A

文章编号:1009-3044(2022)27-0073-03

开放科学(资源服务)标识码(OSID):

本文所涉及的Jinja2模板本质即Python脚本文件,在大型项目中,视图函数把业务逻辑和展现内容集成在一起,使得代码更为复杂,维护成本也更高。使用模板让视图函数只进行业务逻辑方面的业务逻辑和数据处理,视图函数的处理后的数据结果发送到模板进行展示,让代码结构清晰,耦合度大幅降低,开发、维护、更新等成本都大幅降低[1]。

1 Jinja2模板简介

该Python模板文件中包含响应文本,用占位符“{{ }}”标志动态变量位置,模板引擎需要从脚本中标志的动态变量位置获取外部某个具体的值。使用实际的值替换变量占位符的位置,得到最终的字符串,该工作过程为“渲染”。本文讲解的Jinja2模板就是Flask用来进行渲染的模板引擎[2]。

Jinja2模板是一个广泛应用的Python模板引擎,该模板由Python语言实现,其设计思路源于Django的模板引擎,并扩展了Django模板语法和其一系列强大的功能,是Flask框架的内置模板,Flask框架下的render template函数封装了Jinja2模板引擎,该函数的第一个参数是文件名(如index.html),后面的参数都是键值对,表示模板中变量对应的真实值,使用占位符{{}}来表示变量,这里{{}}成为变量代码块,render template函数根据后面传入的参数,对index.html进行渲染[3]。

2 Jinja2模板安全性测试准备

2.1测试环境搭建

测试系统是安全性检测的前置条件,测试环境搭建本着真实、无毒、独立、可复用、前沿、干净、简洁、实用等原则[4],本文Jinja2模板安全性测试环境搭建操作系统采用Windows10专业版,使用Visual Studio Code编程软件 ,使用Python版本为Python3.9的编程语言,安装flask框架(内含jinja2模板)。

项目部分基本源代码如图1所示。

2.2安全性测试方案

访问本地环境:http://127.0.0.1:5000/ ,在URL中使用GET方式传参,“?name=xiaoyi”,页面得到正确的预期响应,回显为“hello,xiaoyi”,整个请求与响应过程分析如图2。

(1)用户通过浏览器提交请求给服务器,Web服务器将请求解包后发给App;

(2)App接收到请求后,通过指定route找到给定的视图函数,然后视图函数处理、渲染后,返回一个响应response;

(3)App将响应返回给服务器的Web服务;

(4)服务器将响应返回给浏览器,浏览器展示出来给用户浏览。

3 Jinja2模板安全性测试

3.1非预期传参测试

功能性测试是系统处理了正常用户请求的过程,下面输入非预期的代码进行测试。输入内容为:{{7*9}},传递到参数进行执行,结果如图3所示:

此时的后台代码执行了7*9,得到运算结果63,所以此时这里就存在安全性问题。接下来进一步构造恶意代码尝试进行远程命令执行。

3.2构造代码实现远程RCE原理

在Python中一切皆是对象,因此很多的基础类都是object类的子类中,想要调用这些类中的方法就需要先通过object类,这样就可以利用子类(这里以str类为例子)来调用父类object类,再利用object类调用其子类os类,从而实现远程RCE(远程命令执行)[5],整个过程如图4所示。

3.3 构造代码实现远程RCE

构造恶意码的具体步骤具体如下:

就是给定一个变量,这个变量可以是int型、str型、bool型、数组、元组、字典、集合等可以识别类型,也可是未定义的类型,从这个变量通过.__class__获取其参数类型,如:

输入:'aa'.__class__ ,返回为class,即字符串型。

再通过__base__返回它的基类(也称父类),如:

输入:'aa'.__class__.__base__ ,返回为class,即object类。

再通過__subclasses__()查询object类中所有子类,并查询到想要用的类的具体位置,本文中以调用os._wrap_close子类为例,输入:'aa'.__class__.__base__.__subclasses__()[134],结果如图5所示。

在Python中所有的类都要经过初始化才能使用,也就是默认调用__init__,因此我们在使用类之前也要调用__init__,通过使用__globals__读出当前的环境变量,输入:{{'aa'.__class__.__base__.__subclasses__()[134].__init__.__globals__}},得到结果如图6所示。

显示当前位于模块os.py中,在该模块中,找到popen方法,进行系统命令执行,输入{{'aa'.__class__.__base__.__subclasses__()[134].__init__.__globals__['popen']('dir').read()}},实现了远程命令执行,结果如图8所示:

4 Jinja2模板安全防护建议

4.1防护思路与方法

针对上面漏洞的防护,思路和其他的注入防御类似,这里对特殊字符自定义黑名单数组blacklist,在获取用户输入的内容后,检测输入内容是否为字符串,再将用户输入的字符串中的字符逐一与blacklist数组中每一个值比较,如若检测到用户输入中存在敏感字符,则提醒用户规范输入,结束程序,反之,如果安全则传入模板,进行渲染,整体应用到Python代码中,实现代码具体如图8所示:

4.2 防护代码安全性测试

对上面防护后代码进行安全性测试,在前端浏览器传入“{}”,返回响应如图9所示,整体测试结果如表1。

根据响应结果分析,用户输入的特殊符号被检测到存在敏感字符,给用户友好提示,并终止程序运行,用户安全输入信息,经过模板正常渲染回显,功能不受影响,从而确保了服务器及数据的安全,是有效的防护措施。

5 总结

本文通过环境搭建、传参测试,发现了Jinja2模板存在的安全性问题,主要是由于开发人员信任了用户的输入,未对用户输入进行审查而导致的,引发了用户可以通过输入恶意代码实现远程RCE,读取服务器内重要信息,甚至获取到服务器的权限。作者对存在的问题进行了系统地分析,制订了问题解决方案,设计了安全编码。经过测试,程序功能正常,能有效防护用户的恶意输入,突显了安全编码的重要性。

参考文献:

[1] 刘丹,李志军,朱书村.基于云端服务检测设备的虚拟控制面板开发[J].吉林大学学报(信息科学版),2021,39(4):463-469.

[2] 任丹,侯英姿,王方雄,等.基于Flask和Vue的AIS数据分析系统设计与开发[J].软件,2019,40(10):111-114,120.

[3] 曾思亮.基于Flask框架的微博用戶分类及推荐系统的实现[D].厦门:厦门大学,2017.

[4] 石春宏.Addslashes函数安全性分析[J].电脑知识与技术,2018,14(33):46,54.

[5] 石春宏.浅议ARP攻击及其防御[J].电脑知识与技术,2016,12(30):26-27.

【通联编辑:梁书】

猜你喜欢
安全性
两款输液泵的输血安全性评估
新染料可提高电动汽车安全性
既有建筑工程质量安全性的思考
某既有隔震建筑检测与安全性鉴定
基于安全性需求的高升力控制系统架构设计
加强广播电视信息安全性的思考
网约车安全性提高研究
注意药酒服用的安全性
基于ASP网站的安全性研究与实现
田间施用灭幼脲在桃中的残留安全性评估