CSRF、XSS、clickjacking、SQL 的攻击与防护

CSRF攻击css

 

原理html

  跨站请求伪造。是一种挟制用户在当前已登陆的Web应用程序上执行非本意的操做的攻击方法。jquery

  网站经过cookie来实现登陆功能。而cookie只要存在浏览器中,那么浏览器在访问含有这个cookie的服务器的时候,会自动的携带cookie信息到服务器上去。就会存在一个漏洞:当你访问了一个病毒网站时,该网站能够在网页源代码中插入js代码,使用js代码给其余服务器发送请求(如ICBC的转帐请求)。由于在发送请求的时候,浏览器会自动的把cookie发送给对应的服务器,这时候相应的服务器(如ICBC网站)不知道这个请求是伪造的,就被欺骗过去了。从而达到在用户不知情的状况下,给某个服务器发送了一个请求(好比转帐)。ajax

 

iframe:正则表达式

  1. 能够加载嵌入别的域名下的网页。便可以发送跨域请求。
  2. 由于iframe加载的是别的域名下的网页。根据同源策略,js只能操做属于本域名下的代码,所以js不能操做经过iframe加载来的DOM元素。
  3. 若是ifrmae的src属性为空,那么就没有同源策略的限制,这时候能够操做iframe下面的代码了。而且,若是src为空,那么能够在iframe中,给任何域名均可以发送请求。
  4. 直接在iframe中写html代码,浏览器是不会加载的。

 

可利用iframe的功能对网站进行攻击sql

例:银行网站的转帐相关简易代码数据库

 1 # 转帐
 2 # 登陆后,进行转帐时确认转帐用户的邮箱及转帐金额;
 3 @method_decorator(login_required,name='dispatch')
 4 class TransferView(View):
 5     def get(self,request):
 6         return render(request,'transfer.html')
 7 
 8     def post(self,request):
 9         form = TransferForm(request.POST)
10         if form.is_valid():
11             email = form.cleaned_data.get('email')
12             money = form.cleaned_data.get('money')
13             # 验证是否有session信息
14             user = request.front_user
15             if user.balance >= money:
16                 User.objects.filter(email=email).update(balance=F('balance')+money)
17                 # 当前用户;
18                 user.balance -= money
19                 user.save()
20                 return HttpResponse('转帐成功!')
21             else:
22                 return HttpResponse('余额不足!')
23         else:
24             print(form.errors)
25             return redirect(reverse('transfer'))

 

攻击方的代码:django

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>首页</title>
 6     <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
 7 </head>
 8 <body>
 9 <!--用户看到的界面图片-->
10 <img src="http://cms-bucket.nosdn.127.net/312e057a25f148519dc02b40812c78fe20170510155251.gif" alt="" width="100%" height="100%">
11 
12 <!--使用iframe,src不加载网页,为空可给任何域名发送请求,添加id的值获取HTML代码-->
13 <iframe id="stealframe" src="" frameborder="0" style="width:0;height:0;">
14 </iframe>
15 <div id="box" style="width: 0;height: 0;">
16         <form action="http://127.0.0.1:8000/transfer/" method="post" id="myform">
17             <input type="text" name="email" value="attacker123@qq.com">
18             <input type="text" name="money" value="100">
19         </form>
20 </div>
21     <script>
22         //获取html=myform的代码
23         window.onload = function () {
24             $('#stealframe').contents().find('html').html($('#myform'));
25             //自动提交代码
26             $('#stealframe').contents().find('html').children('#myform').submit();
27         }
28     </script>
29 </body>
30 </html>

每运行一次攻击者网站,内部将提交一遍 id=form 的html代码, iframe 设置其为不加载该HTML网页但进行网页内部的请求操做。跨域

 

防护CSRF攻击
浏览器

 

  CSRF攻击的要点就是在向服务器发送请求的时候,相应的cookie会自动的发送给对应的服务器。形成服务器不知道这个请求是用户发起的仍是伪造的。这时候,能够在用户每次访问有表单的页面的时候,在网页源代码中加一个随机的字符串叫作 csrf_token ,在cookie中也加入一个相同值的 csrf_token 字符串。之后给服务器发送请求的时候,服务器只有检测到cookie中和网页body中的 csrf_token 都相同,才认为这个请求是正常的,不然就是伪造的。

 

在Django中防护CSRF攻击

  1. settings.MIDDLEWARE中添加 CsrfMiddleware 中间件。
  2. 在模版代码中添加一个input标签,加载 csrf_token 。
    • 模版中添加代码: <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}"/> 
    • 或直接使用‘csrf_token标签’,来自动生成一个带有 csrf token 的‘input标签’: {% csrf_token %} 

 


使用ajax处理csrf防护

  用ajax来处理csrf防护,须要手动的在form中添加csrfmiddlewaretoken,或者是在请求头中添加 X-CSRFToken 。咱们能够从返回的cookie中提取csrf token,再设置进去。

 1 //static:myajax.js
 2 function getCookie(name) {
 3     var cookieValue = null;
 4     if (document.cookie && document.cookie !== '') {
 5         var cookies = document.cookie.split(';');
 6         for (var i = 0; i < cookies.length; i++) {
 7             var cookie = jQuery.trim(cookies[i]);
 8             // Does this cookie string begin with the name we want?
 9             if (cookie.substring(0, name.length + 1) === (name + '=')) {
10                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
11                 break;
12             }
13         }
14     }
15     return cookieValue;
16 }
17 
18 var myajax = {
19     'get': function (args) {
20         args['method'] = 'get';
21         this.ajax(args);
22     },
23     'post': function (args) {
24         args['method'] = 'post';
25         this._ajaxSetup();
26         this.ajax(args);
27     },
28     'ajax': function (args) {
29         $.ajax(args);
30     },
31     '_ajaxSetup': function () {
32         $.ajaxSetup({
33             beforeSend: function(xhr, settings) {
34                 if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type) && !this.crossDomain) {
35                     xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
36                 }
37             }
38         });
39     }
40 };

在模板中导入:

 1 {% load static %}
 2 <!DOCTYPE html>
 3 <html lang="en">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>中国工商银行-转帐</title>
 7     <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
 8     <script src="{% static 'myajax.js' %}"></script>
 9     <script>
10         $(function () {
11             $("#submit").click(function (event) {
12                 event.preventDefault();
13                 var email = $("input[name='email']").val();
14                 var money = $("input[name='money']").val();
15 
16                 myajax.post({
17                     'url': '/transfer/',
18                     'data': {
19                         'email': email,
20                         'money': money
21                     },
22                     'success': function (data) {
23                         // 若是状态码是等于200才会走到success的回调中
24                         console.log(data);
25                     },
26                     'fail': function (error) {
27                         console.log(error);
28                     }
29                 });
30             });
31         });
32     </script>
33 </head>
34 --snip--

 

 

XSS攻击:

  跨站脚本攻击。是一种网站应用程序的安全漏洞攻击,是代码注入的一种,利用网页开发时留下的漏洞,注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。

  好比A网站有一个发布帖子的入口,若是用户在提交数据的时候,提交了一段js代码 <script>alert("hello world");</script> ,而后A网站在渲染这个帖子的时候,直接把这个代码渲染了,那么这个代码就会执行,会在浏览器的窗口中弹出一个模态对话框来显示 hello world! ,攻击者可利用该漏洞进行攻击。

<li>&lt;script&gt;alert(&quot;Hello world&quot;)&lt;/script&gt;</li>

 

防护:

  1. 若是不须要显示一些富文本,那么在渲染用户提交的数据的时候,直接进行转义。在Django的模板中默认就是转义的。也能够把数据在存储到数据库以前,先转义再存储进去,这样之后在渲染的时候,即便不转义也不会有安全问题。
    1 # 使用escape在存储前先进行转义
    2 @require_http_methods(['POST'])
    3 def add_comment(request):
    4     content = request.POST.get('content')
    5     content = escape(content)
    6     Comment.objects.create(content=content)
    7     return redirect(reverse('index'))

     

  2. 若是对于用户提交上来的数据包含了一些富文本(好比:给字体换色,字体加粗等),在渲染的时候也要以富文本的形式进行渲染,也即须要使用 safe过滤器 将其标记为安全的,这样才能显示出富文本样式,但标签全经过会有安全隐患。因此可使用 bleach库 的 sanitizer ,在服务器处理数据的时候,将须要的标签保留下来,把那些不须要的标签进行转义或者移除掉。
    1 <!--html模板代码-->
    2 <!--safe会经过全部的标签-->
    3     {% for comment in comments %}
    4         <li>{{ comment.content | safe}}</li>
    5     {% endfor %}
     1 # 使用bleach库
     2 
     3 from django.shortcuts import render,redirect,reverse
     4 from .models import Comment
     5 from django.views.decorators.http import require_http_methods
     6 from django.template.defaultfilters import escape
     7 import bleach
     8 from bleach.sanitizer import ALLOWED_TAGS,ALLOWED_ATTRIBUTES
     9 
    10 # 首页,显示出数据库中comments全部的值,
    11 def index(request):
    12     context = {
    13         'comments':Comment.objects.all()
    14     }
    15     return render(request,'index.html',context=context)
    16 
    17 # 将提交的数据保存并返回首页
    18 @require_http_methods(['POST'])
    19 def add_comment(request):
    20     content = request.POST.get('content')
    21     # 在bleach库已默认容许经过的标签、属性上再添加须要的新标签及属性
    22     tags = ALLOWED_TAGS + ['img']
    23     attributes = {**ALLOWED_ATTRIBUTES,'img':['src']}
    24     # 对提交的数据进行过滤
    25     cleaned_data = bleach.clean(content,tags=tags,attributes=attributes)
    26     Comment.objects.create(content=cleaned_data)
    27     return redirect(reverse('index'))

     

bleach库:

  • tags:表示容许哪些标签。
  • attributes:表示标签中容许哪些属性。
  • ALLOWED_TAGS:默认定义的一些标签。若是不符合要求,能够对其进行增长或者删除。
  • ALLOWED_ATTRIBUTES:默认定义的一些属性。若是不符合要求,能够对其进行增长或者删除。

 

clickjacking攻击:

  又称做点击劫持攻击。是一种在网页中将恶意代码等隐藏在看似无害的内容(如按钮)之下,并诱使用户点击的手段。

两种攻击方式:

  1. 攻击者使用一个透明的iframe,覆盖在一个网页上,而后使用户在该页面上进行操做,如网页包含了一个按钮A,按钮上面浮了一个透明的iframe标签,用户将在不知情的状况下点击透明的iframe页面进行加载。
  2. 攻击者使用一张图片覆盖在网页,遮挡网页原有位置的含义;如用户收到一封包含一段视频的电子邮件,但其中的“播放”按钮并不会真正播放视频,而是链入一购物网站。这样当用户试图“播放视频”时,实际是被诱骗而进入了一个购物网站。
1 # clickjacking攻击
2 def index(request):
3     return render(request,'clickjacking.html')
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>点击劫持</title>
 6     <style>
 7         iframe{
 8             width:100%;
 9             height:100%;
10             display:block;
11             position: absolute;
12             z-index: 2;
13             opacity: 0.01;
14         }
15         button{
16             position: absolute;
17             top: 45px;
18             left: 180px;
19             z-index: 1;
20         }
21     </style>
22 </head>
23 <body>
24 点击下方的按钮将会进行跳转:
25 <button>跳转按钮</button>
26 <iframe src="https://www.bilibili.com/video/av21663728/?p=33" frameborder="0"></iframe>
27 </body>
28 </html>

z-index :设置元素的堆叠顺序。拥有更高堆叠顺序的元素老是会处于堆叠顺序较低的元素的前面。

position: 规定元素的定位类型。

opacity :设置元素的不透明级别。

 

clickjacking防护

  设置网站不容许使用iframe被加载到其余网页中,就能够避免这种攻击。能够经过在响应头中设置 X-Frame-Options 来设置这种操做。

X-Frame-Options 可设置的值:

  • DENY:不让任何网页使用iframe加载该页面。
  • SAMEORIGIN:只容许在相同域名(即本人的网站)下使用iframe加载该页面。
  • ALLOW-FROM origin:容许任何网页经过iframe加载该网页。

  在Django中可以使用中间件 django.middleware.clickjacking.XFrameOptionsMiddleware ,这个中间件设置了“X-Frame-Option”为 SAMEORIGIN ,即在同域名的网站下才可使用iframe加载这个网页,可避免被攻击者经过iframe去加载了。

 

SQL注入

 

  经过把SQL命令插入到表单中或页面请求的查询字符串中,程序忽略了字符检查,最终达到欺骗服务器执行恶意的SQL命令。利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,经过在Web表单中输入(恶意)SQL语句获得一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 

 

下方代码在网页输入 ?username=*** 时,可在后面再添加内容进行注入攻击:

 1 # SQL注入攻击
 2 def index(request):
 3     username = request.GET.get('username')
 4     context = {}
 5     if username:
 6         cursor = connection.cursor()
 7         cursor.execute("select id,username from front_user where username='%s'" % username)
 8         rows = cursor.fetcall()
 9         context['rows'] = rows
10     return render(request,'sql.html',context=context)

当输入 ?usename=***'or'1=1 时:

1 # 若是输入:http://127.0.0.1:8000/?username=jack'or'1+1 而不是只输入:http://127.0.0.1/?username=jack
2 sql = "select id,username from front_user where username='%s'" % "jack ' & '1=1"
3 # 代码内容将会被改变
4 sql = "select id,username from front_user where username='jack' or '1=1'"

这将会显示出全部的内容而不仅仅一个;

 

sql注入防护:

  • 不要信任用户的输入。对用户的输入进行校验,能够经过正则表达式,或限制长度;对单引号和 双"-"进行转换等。
  • 不要使用动态拼装sql,可使用参数化的sql或者直接使用存储过程进行数据查询存取。
  • 不要使用管理员权限的数据库链接,为每一个应用使用单独的权限有限的数据库链接。
  • 不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
  • 应用的异常信息应该给出尽量少的提示,最好使用自定义的错误信息对原始错误信息进行包装。
     1 # 使用参数化
     2 def index(request):
     3     username = request.GET.get('username')
     4     context = {}
     5     if username:
     6         cursor = connection.cursor()
     7         sql = 'select id,username from front_user where username=%s'
     8         cursor.execute(sql,(username,))
     9         rows = cursor.fetchall()
    10         context['rows'] = rows
    11     return render(request,'sql.html',context=context)

     

Django防护sql注入:

  • 使用ORM来作数据的增删改查。由于ORM使用的是参数化的形式执行sql语句的。
  • 若是万一要执行原生sql语句,那么建议不要拼接sql,而是使用参数化的形式。