XSS攻击
什么是XSS攻击
XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如 同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的 网络钓鱼(Phishing)攻击而变得广为人知。对于 跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“ 缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。
实施XSS攻击需要具备两个条件:
一、需要向web页面注入恶意代码;
二、这些恶意代码能够被浏览器成功的执行。
解决办法:
1、一种方法是在表单提交或者url参数传递前,对需要的参数进行过滤。
2、在后台对从数据库获取的字符串数据进行过滤,判断关键字。
3、设置安全机制。
django框架:内部机制默认阻止了。它会判定传入的字符串是不安全的,就不会渲染而以字符串的形式显示。如果手贱写了safe,那就危险了,若想使用safe,那就必须在后台对要渲染的字符串做过滤了。所以在开发的时候,一定要慎用安全机制。尤其是对用户可以提交的并能渲染的内容!!!
- 示例:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8 <form method="POST" action="/comment/">
9 <h4>评论</h4>
10 <input type="text" name="content"/>
11 <input type="submit" value="提交" />{{ error }}
12 </form>
13 </body>
14 </html>
评论提交页面
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8 <h1>评论内容</h1>
9 {% for item in msg %}
10 <div>{{ item|safe }}</div>
11 {% endfor %}
12 </body>
13 </html>
评论显示页面
1 from django.shortcuts import render
2 msg = []
3 def comment(request):
4 if request.method == "GET":
5 return render(request,'comment.html')
6 else:
7 v = request.POST.get('content')
8 if "script" in v:
9 return render(request,'comment.html',{'error': '小比崽子还黑我'})
10 else:
11 msg.append(v)
12 return render(request,'comment.html')
13
14 def index(request):
15 return render(request,'index.html',{'msg':msg})
16
17 def test(request):
18 from django.utils.safestring import mark_safe
19 temp = "<a href='http://www.baidu.com'>百度</a>"
20 newtemp = mark_safe(temp)
21 return render(request,'test.html',{'temp':newtemp}
后台处理
CSRF跨站请求伪造
什么是 CSRF
CSRF, Cross Site Request Forgery, 跨站点请求伪造。举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用户点击这个恶意网站上的那个链接时,就会向你的网站发来一个请求,你的网站会以为这个请求是用户自己发来的,其实呢,这个请求是那个恶意网站伪造的。
csrf攻击过程
1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
3.用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
4.网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
5.浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
csrf的攻击之所以会成功是因为服务器端身份验证机制可以通过Cookie保证一个请求是来自于某个用户的浏览器,但无法保证该请求是用户允许的。因此,预防csrf攻击简单可行的方法就是在客户端网页上添加随机数,在服务器端进行随机数验证,以确保该请求是用户允许的。Django也是通过这个方法来防御csrf攻击的。
在django防御csrf攻击
原理
在客户端页面上添加csrftoken, 服务器端进行验证,服务器端验证的工作通过'django.middleware.csrf.CsrfViewMiddleware'这个中间层来完成。在django当中防御csrf攻击的方式有两种, 1.在表单当中附加csrftoken 2.通过request请求中添加X-CSRFToken请求头。注意:Django默认对所有的POST请求都进行csrftoken验证,若验证失败则403错误侍候。
在表单中附加csrftoken
后端
1 from django.shortcuts import render
2 from django.template.context_processors import csrf
3
4 def ajax_demo(request):
5 # csrf(request)构造出{‘csrf_token’: token}
6 return render(request, 'post_demo.html', csrf(request))
前端
1 $('#send').click(function(){
2
3 $.ajax({
4 type: 'POST',
5 url:'{% url 'ajax:post_data' %}',
6 data: {
7 username: $('#username').val(),
8 content: $('#content').val(),
9 'csrfmiddlewaretoken': '{{ csrf_token }}' 关键点
10 },
11 dataType: 'json',
12 success: function(data){
13
14 },
15 error: function(){
16
17 }
18
19 });
20 });
View Code
通过request请求中添加X-CSRFToken请求头
后端
该方式需要借助于Cookie传递csrftoken, 设置Cookie的方式有两种。ps:经测试即便什么都不做,也会设置Cookie,不过官方文档说,不保证每次都有效
1.表单中添加{%csrf_token%}这个模板标签
1 <form id="comment_form" action="#"></form>
2 {% csrf_token %} 就是这个
3 <p>姓名: <input type="text" name="useranme" id="username"></p>
4 <p>内容: <textarea name="content" id="content" rows="5" cols="30"></textarea></p>
5 <p><input type="button", id="send" value="提交"></p>
2.ensure_csrf_cookie装饰器
1 from django.shortcuts import render
2 from django.views.decorators.csrf import ensure_csrf_cookie
3
4 @ensure_csrf_cookie
5 def ajax_demo(request):
6 return render(request, 'ajax_demo.html')
前端
前端要做的事情,在进行post提交时,获取Cookie当中的csrftoken并在请求中添加X-CSRFToken请求头, 该请求头的数据就是csrftoken。通过$.ajaxSetup方法设置AJAX请求的默认参数选项, 在每次ajax的POST请求时,添加X-CSRFToken请求头
1 <script type="text/javascript">
2 $(function(){
3
4 function getCookie(name) {
5 var cookieValue = null;
6 if (document.cookie && document.cookie != '') {
7 var cookies = document.cookie.split(';');
8 for (var i = 0; i < cookies.length; i++) {
9 var cookie = jQuery.trim(cookies[i]);
10 // Does this cookie string begin with the name we want?
11 if (cookie.substring(0, name.length + 1) == (name + '=')) {
12 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
13 break;
14 }
15 }
16 }
17 return cookieValue;
18 }
19
20 <!--获取csrftoken-->
21 var csrftoken = getCookie('csrftoken');
22 console.log(csrftoken);
23
24 //Ajax call
25 function csrfSafeMethod(method) {
26 // these HTTP methods do not require CSRF protection
27 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
28 }
29
30 $.ajaxSetup({
31 crossDomain: false, // obviates need for sameOrigin test
32 //请求前触发
33 beforeSend: function(xhr, settings) {
34 if (!csrfSafeMethod(settings.type)) {
35 xhr.setRequestHeader("X-CSRFToken", csrftoken);
36 }
37 }
38 });
39
40 $('#send').click(function(){
41 console.log($("#comment_form").serialize());
42
43 $.ajax({
44 type: 'POST',
45 url:'{% url 'ajax:post_data' %}',
46 data: {
47 username: $('#username').val(),
48 content: $('#content').val(),
49 //'csrfmiddlewaretoken': '{{ csrf_token }}'
50 },
51 dataType: 'json',
52 success: function(data){
53
54
55 },
56 error: function(){
57
58 }
59
60 });
61 });
62
63
64 });
65 </script>
取消csrftoken验证
通过csrf_exempt, 来取消csrftoken验证,方式有两种。
1 .在视图函数当中添加csrf_exempt装饰器
1 from django.views.decorators.csrf import csrf_exempt
2
3 @csrf_exempt
4 def post_data(request):
5 pass
2 .在urlconf当中
1 from django.views.decorators.csrf import csrf_exempt
2 urlpatterns = [
3 url(r'^post/get_data/$', csrf_exempt(post_data), name='post_data'),
4
5 ]
django csrf注意点:
注意一定注意:ajax POST提交的时候,csrf-token 随机字符串 直接放在data数据中的方式为:****data:{csrfmiddlewaretoken:"{{ csrf_token }}"}
若是导入自己写的JS文件,那上述方法就不能获取到Django后台发送的随机字符串,而是需要利用上面介绍的两种方式获取(页面写上{% csrf_token %},通过隐藏的input标签取value值写在POST提交的data数据中;或是从cookie中获取,写在头文件中。)
使用django框架时:
每次初始化一个项目时都要看看 django.middleware.csrf.CsrfViewMiddleware 这个中间件
每次在模板里写 form 时都需要加一个 {% csrf_token %} tag
每次发 ajax POST 请求,都需要加一个 X_CSRFTOKEN 的 header
流程:
用户第一次访问页面,肯定是get请求,此时服务端就会给客户端发送一段随机字符串的数据,当客户提交数据的时候,常在POST请求中带回,就会发送随机字符串给服务端(上一次请求获取的数据)用于验证。
服务端给客户端发送的随机字符串作为一种安全机制,客户端往服务端发送请求时再携带回来,用于匹配认证。
可以从form表单中接收,也可以在cookies中查看,注意:这两个的随机字符串是不同的!
如果开启了csrf认证,后台没有拿到对应的字符串的话就会报错---> 403