CSRF ( cross site request forgery ) 跨站点请求伪造
假如有一个恶意的网站链接指向我的网站链接,如果当前某个用户已经登录到我的网站上,那么当恶意网站的用户点击这个链接时,我的网站以为是当前用户发生的请求,但其实是恶意网站伪造的请求。django 第一次响应来自某个客户端的请求时,会在服务器随机生成一个token值,把该token值放在cookie中,然后每次POST请求都会带上这个token值,防止恶意网站请求伪造,避免发生CSRF攻击。
Django 里如何使用 CSRF 防护
首先,最基本的原则是:GET 请求不要存在副作用。也就是说任何处理 GET 请求的代码对资源的访问都一定要是“只读“的。
启用 django.middleware.csrf.CsrfViewMiddleware 这个中间件
其次,在所有的 POST 表单元素时,需要加上一个
{% csrf_token %}
标签在渲染模块时,使用 RequestContext。RequestContext 会处理 csrf_token 这个标签, 从而自动为表单添加一个csrfmiddlewaretoken 的 input标签
会话技术
HTTP被设计为”无状态”,每次请求都处于相同的空间中。在一次请求和下一次请求之间没有任何状态保持,我们无法根据请求的任何方面(IP地址,用户代理等)来识别来自同一人的连续请求。上图很明显的展示了Django的session与cookie的实现原理。服务器会生成两份相同的cookie字符串,一份保存在本地,一份发向请求的浏览器。浏览器将收到的cookie字符串保存下来,当下次再发请求时,会将信息与这段cookie一同发送到服务器,服务器得到这段cookie会与本地保存的那份判断是否相同,如果相同就表示用户已经登录成功,保存用户登录成功的状态。Django的session保存在数据库中的数据相当于一个大字典,key为cookie的字符串,value仍是一个字典,字典的key和value为用户设置的相关信息。这样就可以方便的存取session里面的信息。
- 验证用户身份信息
- 服务器如何识别客户端
- Http在Web开发中基本都是短连接
- 请求生命周期
- 从Request开始
- 到Response结束
种类
1. Cookie
-
客户端会话技术,数据存储在客户端
-
存储形式:键值对存储
-
特性:
- 支持过期时间
- 默认Cookie会自动携带本网站所有的Cookie
- Cookie不能跨域名,不能跨网站
- 通过HttpResponse操作客户端
-
Django中使用Cookie
# 设置cookie,从服务器返回的response中设置 response = redirect(path) # 重定向到某个指定的路径下 response.set_cookie(key,value,max_age=0) # 直接设置cookie的值和value,max_age是过期时间,0是默认,None是永久,接上数字是具体时间,用s做单位。 如:response.set_cookie('name',person.name,max_age=3600) # 获取cookie,从客户端请求中获得 name = request.COOKIES.get('name') response = render(request,'home.index',contex=({'name':name}) return response # 清除cookie,从response清除 response = redirect('namespace:name') response.delete_cookie('name')
~ 读取请求头中的cookie信息:request.COOKIES - [key] -> value ~ 通过响应将cookie写入浏览器:response.set_cookie(key, value, 时间) ~ 删除cookie:自动过期 / response.delete_cookie(key) ~ 如果要防范恶意的伪造或篡改cookie,可以使用带签名的cookie - response.set_signed_cookie(key, value, salt, 时间) - request.get_signed_cookie(key, salt)
2. Session
-
服务端会话技术,数据存储在服务器中
-
默认Session存储在内存中
-
Django默认把Session持久化到数据库中
-
Django中Session的默认过期时间是14天
-
Primary key 是字符串
-
数据存储使用了数据安全
-
使用了Base64编码:将任意的二进制数据处理成64个文字符号(0-9a-zA-Z+/)的编码方法
Python:b64encode() 编码 / b64decode()解码
JavaScript:btoa()编码 / atob() 解码 – 较新版本的浏览器
百分号编码 - URL中不能出现非ASCII码字符,有些字符还有特殊含义,
如果URL中出现了非ASCII码字符和特殊符号必须处理成百分号编码
~ Python - quote() 编码 / unquote() 解码
~ JavaScript - encodeURIComponent() / decodeURIComponent()In [1]: from urllib.parse import quote, unquote In [2]: quote('苹果') Out[2]: '%E8%8B%B9%E6%9E%9C' In [3]: a = 'https://www.baidu.com' In [4]: a + quote('苹果') Out[4]: 'https://www.baidu.com%E8%8B%B9%E6%9E%9C' In [5]: a = 'https://www.baidu.com/?' In [6]: a + quote('苹果') Out[6]: 'https://www.baidu.com/?%E8%8B%B9%E6%9E%9C' In [7]: unquote('https://www.baidu.com/?%E8%8B%B9%E6%9E%9C') Out[7]: 'https://www.baidu.com/?苹果' In [8]:
-
在前部添加了混淆串
-
-
Cookie和Session的关系:session依赖于cookie,cookie中保存了session的标识符,每次请求服务器,请求头都会携带cookie,这样就可以将session表示符发送给服务器,服务器通过该标识符获取到跟请求对应的session对象
-
Django中是使用session
# 设置session,一开始需要在project中setting里的middleware中添加上'django.contrib.sessions.middleware.SessionMiddleware', #默认是加上的,在request中设置session request.session['name'] = person.name request.session.set_expiry(60) # 设置过期时间,单位是s # 获取session,也是从request中获取 name = request.session.get('name') # 删除session,在response中删除 response.delete_cookie('sessionid') # 在客户端删除session del request.session['name'] # 在服务器端删除session request.session.flush()
-
过期时间
settins.py 文件中添加:
# 配置将会话放入缓存中 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 配置缓存的过期时间为1天 SESSION_COOKIE_AGE = 86400
3. Token
使用Python中uuid函数来生成用户的令牌
- uuid1():这个是根据当前的时间戳和MAC地址生成的,最后的12个字符408d5c985711对应的就是MAC地址,因为是MAC地址,那么唯一性应该不用说了。但是生成后暴露了MAC地址这就很不好了。
- uuid3():里面的namespace和具体的字符串都是我们指定的,然后呢···应该是通过MD5生成的,这个我们也很少用到,莫名其妙的感觉。
- uuid4():这是基于随机数的uuid,既然是随机就有可能真的遇到相同的,但这就像中奖似的,几率超小,因为是随机而且使用还方便,所以使用这个的还是比较多的。
- uuid5():这个看起来和uuid3()貌似并没有什么不同,写法一样,也是由用户来指定namespace和字符串,不过这里用的散列并不是MD5,而是SHA1.
# 如果需要在MySQL中存储token需要建立有关token字段的表格 / redis / mongodb
import uuid
token = uuid.uuid4().hex # 使用uuid创建token
response.set_cookie('token', token) # 将token传给浏览器
# 获取token,在request中获取token
person.token = request.COOKIES.get('token')
# 清除token,在response中清除
response.delete_cookie('token')
在存储session,cookie,token的时候还应该对用户的信息进行加密(MD5 / SHA1)