字符串过滤html标签(过滤字符串中的选定字符)

  1

前言

  Flask 是python语言编写的轻量级的MVC (也可以称为MTV, T: Template)框架具体详见http://docs.jinkan.org/docs/flask/

  对于Flask 框架本身,本文不做讨论。

  本文主要通过几个例子,测试说明下Flask框架中服务端模板注入带来的安全隐患

  2

测试Code

  fromflask importFlask, request, render_template_string, render_template

  app = Flask(__name__)

  @app.route('/hello-template-injection')

  defhello_ssti():

  person = {'name': "world", 'secret': "UGhldmJoZj8gYWl2ZnZoei5wYnovcG5lcnJlZg=="}

  ifrequest.args.get('name'):person['name'] = request.args.get('name')template = '''<h2>Hello %s!</h2>'''% person['name']

  returnrender_template_string(template, person=person)

  @app.route('/hello-xss')

  defhello_xss():name = "world"

  template = 'hello.unsafe'# 'unsafe' file extension... totally legit.

  ifrequest.args.get('name'):name = request.args.get('name')

  returnrender_template(template, name=name)

  @app.route('/html-attribute-xss')

  defhello_hi():

  template = '''<title>No Injection Allowed!</title><a href={{ url_for('hello_xss')}}?name={{ name |e}}>Click here for a welcome message</a>'''name = "world"

  ifrequest.args.get('name'):name = request.args.get('name')

  returnrender_template_string(template, name=name)

  ####

  # Private function if the user has local files.

  ###

  defget_user_file(f_name):

  withopen(f_name) asf:

  returnf.readlines()app.jinja_env.globals['get_user_file'] = get_user_file# Allows for use in Jinja2 templates

  if__name__ == "__main__":app.run(debug=True)

  3

模板字符串中字符串拼接或替换引发的安全隐患

  我们看一下测试代码中的 hello_ssti函数

  函数中模板内容

  template = '''<h2>Hello %s!</h2>'''% person['name']

  就是简单的字符串替换,这会引发什么安全问题吗?

  我们看例子:

  运行后,浏览器访问: http://localhost:5000(Flask开发的程序,默认监听端口为5000)

  

  OK, 打印Hello World。

  但是,如果传入的name 参数值为恶意代码会怎么样?

  引发敏感信息泄露

  http://localhost:5000/hello-template-injection?name=ForrestX386. {{person.secret}}

  

  secret 值被泄露

  原因:

  我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换,如果传入的name=ForrestX386. {{person.secret}},那么在模板渲染的时候就会将{{}}替换成字典person中secret元素的值

  **引发本地文件包含漏洞**

  http://localhost:5000/hello-template-injection?name=ForrestX386. {{get_user_file('E:haha.txt')}}

  

  E:haha.txt 内容被泄露

  原因:

  同上,Jinja2在渲染模板的时候,将{{get_user_file(‘E:haha.txt’)}}的内容替换成get_user_file(‘E:haha.txt’)函数的返回值

  如何解决上述问题:

  将template = ”’<h2>Hello %s!</h2>”’ % person['name']

  更改为template = ”’<h2>Hello {{person['name']}}!</h2>”’

  这样以来,Jinja2在模板渲染的时候将person['name']的值替换掉{{person['name']}}, 而不会对person['name']内容进行二次渲染(这样即使`person['name']中含有{{}}也不会进行渲染,而只是把它当做普通字符串)

  4

字符串过滤html标签(过滤字符串中的选定字符),字符串过滤html标签(过滤字符串中的选定字符),字符串过滤html标签,信息,模板,浏览器,第1张

render_template_string 的安全隐患

  我们知道Flask render_template函数在模板渲染(使用Jinja2模板引擎)的时候,会自动对模板(常见的模板后缀才进行自动HTML转码,比如.html,.htm等,不常见的模板后缀是不会进行HTML自动编码的,下面会介绍到)内容进行HTML实体编码,从而避免XSS漏洞的发生,但是Flask中的render_template_string 函数却不会对要渲染的模板字符串进行自动HTML实体编码,存在XSS安全隐患

  下面看一个例子

  引发XSS

  

  http://localhost:5000/hello-template-injection?name=ForrestX386. <>alert(“welcome to visit ForrestX386.github.io.”)</>

  确实发生了XSS弹窗,说明render_template_string 函数没有进行自动HTML实体编码

  注:

  如果你在测试过程中使用的是chrome浏览器,且没有弹框,请把chrome XSS 过滤器给关闭你可以这样关闭chrome xss 过滤器

  在目标后面加上`–args –disable-xss-auditor `

  

  确定,重启chrome,就可以了

  如何解决上述问题

  我们可以在输出的内容后面加上`| e`,这样就要求Jinja2模板引擎 将输出内容HTML实体编码后再输出给用户

  template= '<h2>Hello {{ person['name'] | e }}!</h2>'

  恩,这样就不会有XSS 漏洞了

  

  5

使用不常见的模板后缀引发的安全隐患

  我们看一下测试代码中的hello_xss 方法,其中模板为`template = ‘hello.unsafe’`, 后缀unsafe 不是Jinja2模板引擎支持的自动HTML编码的模板后缀,如果编写模板内容的时候不够细心或者考虑不周全,则可能引发XSS漏洞。

  看下面的例子

  如果hello.unsafe模板内容是这样的:

  {% autoescape true %}

  <h2>Good</h2>

  <p>

  Hello {{ name }}! I don't trust your input. I escaped it, just in case.

  </p>

  {% endautoescape %}<h2>Bad</h2><p>I trust all data! How are you {{ name }}?

  </p>

  区块Good 使用Jinja2中autoescape方法,而区块Bad 没有使用,我们访问下面的url看看会发生什么

  http://localhost:5000/hello-xss?name=ForrestX386.<>document.title="xss";</>

  

  是的,使用autoescape方法的区块没有XSS漏洞(autoescape函数会自动将所包裹区块自动HTML实体编码),而没有使用autoescape方法的区块(Bad区块)发生XSS漏洞,说明render_template是不会对不支持自动HTML实体编码的模板后缀进行自动HTML实体编码

  所以当使用render_template渲染Jinja2模板引擎不支持自动HTML实体编码的模板后缀的时候,请小心仔细一些,在有用户输入的的地方使用autoescape方法

  如何解决上述问题

  除了使用autoescape方法,我们还可以在要渲染的内容后面加上` |e `进行HTML实体编码比如将Bad 区块内容更改为

  <h2>Bad</h2>

  <p>

  I trust all data! How are you {{ name |e }}?

  </p>

  这样就不会有XSS漏洞了

  

  6

利用模板中html标签属性字段绕过xss过滤

  我们在4节谈到了render_template_string 不会对要渲染的字符串进行自动HTML实体编码转换,但是可以使用|e 对输出内容进行HTM实体编码转换,那么使用`|e`一定安全吗? 那倒不一定,不信看看下面的测试:

  举个栗子

  我们看一下测试代码中的hello_hi方法

  @app.route('/html-attribute-xss')

  defhello_hi():

  template = '''<title>No Injection Allowed!</title>

  <a href={{ url_for('hello_xss')}}?name={{ name |e}}>Click here for a welcome message</a>'''

  name = "world"

  ifrequest.args.get('name'):name = request.args.get('name')returnrender_template_string(template, name=name)

  虽然使用|e 进行html实体转义 ,但我们可以通过下面的方式进行绕过浏览器访问:

  http://localhost:5000/html-attribute-xss?name=testonmouseover=document.title="xss-again"

  打开的界面是这样的:

  

  当我们把鼠标放在超链接上的时候

  

  注意到没有 title 变成了xss-again,说明xss注入成功

  原因:

  name 参数传入的值为test onmouseover=document.title=”xss-again”,替换之后变成

  <a href={{ url_for('hello_xss')}}?name=testonmouseover=document.title="xss-again">

  因为注入的name参数值渲染后出现在了HTML标签的属性值中,而|e 是不会对属性值进行HTML转义过滤的

  如何解决:

  只要使用单引号或者双引号将href的值括起来就可以了

  <ahref="{{ url_for('hello_xss')}}?name={{ name |e}}">

  7

总结

  通过上面的例子,我们总结了再Flask框架中使用模板可能带来的一些安全隐患以及对应的解决方法,让我们了解了使用模板中一些tips。

  总之,我们在使用Flask开发的时候,一定要谨记:用户的任何输入都是不可信的,要在输入和输出端都做好过滤Origin Refer:https://nvisium.com/blog/2015/12/07/injecting-flask/

  完

  作者ForrestX386,来自FreeBuf

  炼石信息安全培训班

专注信息安全人才培养

搭建企业人才供需桥梁

咨询QQ群:495066536

1、本网站名称:源码村资源网
2、本站永久网址:https://www.yuanmacun.com
3、本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
源码村资源网 » 字符串过滤html标签(过滤字符串中的选定字符)

1 评论

您需要 登录账户 后才能发表评论

发表评论

欢迎 访客 发表评论