tanrong 2019-12-20
一、csrf跨站请求伪造(Cross-site request forgery)
CSRF的攻击原理:简单说就是利用了高权限帐号(如管理员)的登录状态或者授权状态去做一些后台操作,但实际这些状态并没有被我们直接获取到(获取那是XSS干的事)。
CSRF能够攻击的根本原因是:服务器无法识别你的来源是否可靠。
防御CSRF攻击:服务端验证请求的token一致性
CSRF攻击的核心原理就是利用用户验证信息储存cookie中,发送请求,使得服务器无法判断真伪,而token之所以能够拦截,就是因为它是CSRF攻击过程中几乎不可能伪造的东西。
实现原理:在服务端生成一个随机的token,加入到HTTP请求参数中,服务器拦截请求,查看发送的token和服务端的是否一致,若一致,则允许请求;若不一致,则拒绝请求。
django项目setting.py里MIDDLEWARE就自带有django.middleware.csrf.CsrfViewMiddleware,再配合模板里的表单以post方式提交时添加的{% csrf_token %}就是采用此原理实现。但是有的项目采用前后端分离,就需要后端手动生成token发送给前端。
关于生成token:可以参考https://www.cnblogs.com/hooo-1102/p/12048232.html
二、xss跨站脚本攻击(Cross Site Scripting)
xss的攻击原理:通过对网页注入可执行代码且成功地被浏览器 执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨大的,是web安全的头号大敌
下面举个栗子,比较简单:
前端:
后端:
json_str = request.body if not json_str: result = {‘code‘:302, ‘error‘: ‘Please give me data‘} return JsonResponse(result) json_obj = json.loads(json_str) title = json_obj.get(‘title‘) if not title: result = {‘code‘:303, ‘error‘: ‘Please give me title !!‘} return JsonResponse(result) #防止xss cross site script 攻击 title = html.escape(title)
对前端传过来的title进行了html.excape()处理,可以对相应的字符进行转义,标题下面的大文本框是第三方的,应该做了相应的处理,不需要我们再进行转义
三、sql注入
所谓SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串(注入本质上就是把输入的字符串变成可执行的程序语句),最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。在Web应用漏洞中,SQL Injection 漏洞的风险要高过其他所有的漏洞。
举个栗子:
前端就是一个简单的登录表单,
后端
from django.shortcuts import render, HttpResponse, redirect from django.views.generic.base import View class LoginNotSafeView(View): def get(self, request): return render(request, ‘login.html‘) def post(self, request): user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") import pymysql conn = pymysql.connect(host=‘127.0.0.1‘, port=3306, user=‘root‘, password=‘123456‘, db=‘mxonline‘,charset=‘utf8‘ ) cursor = conn.cursor() # 黑客可通过user或者password输入数据库语句对数据非法利用 sql_select = " select * from users_userprofile where username=‘{0}‘ and passworf=‘{1}‘ ".format(user_name, pass_word) result = cursor.execute(sql_select) for i in cursor.fetchall(): # 数据库所有查询结果 pass
如果在前端的username框中填写admin,password为123,
上面
sql_select = " select * from users_userprofile where username=‘{0}‘ and passworf=‘{1}‘
相当于
select * from users_userprofile where username=admin and passworf=123
但是如果在前端username框中填写admin or admin=admin #,password为123
现在就成这样了:
select * from users_userprofile where username=admin or admin = admin # and passworf=123
这里的#相当于把后面的所有查询包括password查询给注释,并且
or admin = admin
的查询永远是正确的,所以sql攻击注入就完成了
防御sql注入攻击:
总是使用Django自带的数据库API
对用户的输入进行校验,可以通过正则表达式限制长度;对单引号和双"-"进行转换等。
不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。