Django会话安全

Django会话机制

Django中默认支持Session,Django有一个会话框架来处理Cookies。使用之前,需要配置下Django 的缓存框架。可以通过settings.py中的MIDDLEWARE_CLASSES和INSTALLED_APPS进行Session设置。

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = (
# 启用sessions应用
'django.contrib.sessions',
)

MIDDLEWARE_CLASSES = (
# 启用session 中间件
'django.contrib.sessions.middleware.SessionMiddleware',
)

Django内部提供了5种类型的Session供开发者使用,通过在 settings.py 中增加 SESSION_ENGINE 配置实现

  • 数据库(默认):SESSION_ENGINE =’django.contrib.sessions.backends.db’ Django 默认是将 Session 数据存储在数据库中,即:django_session 表中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 配置settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
    SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key, 即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 (默认)
    SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修 改之后才保存(默认)
  • 缓存:SESSION_ENGINE = ‘django.contrib.sessions.backends.cache’ 需要快速存储会话的场景,可以选择将 Session 保存到缓存中。 这种配置方案 Django 只是简单保存会话。同时,这种方案持久性不好。因为当缓存 数据存满时将清除部分数据,或者遇到缓存服务器重启时数据将丢失。

    1
    2
    3
    4
    # 配置settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
    SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以 是memcache),此处别名依赖缓存的设置
    # 其他配置与db方式一致
  • 文件:SESSION_ENGINE = ‘django.contrib.sessions.backends.file’

    这种方案是保存数据到本地磁盘中。因为磁盘的 I/O 瓶颈问题,导致这种方案存储数 据效率不是很高。

    可选配置:SESSION_FILE_PATH = ‘/monkey/www/‘

    SESSION_FILE_PATH 默认使用 tempfile.gettempdir() 方法的返回值,就像 /tmp 目录。

    如果你想更新文件的保存路径,可以手动指定。另外需确保你的文件存储目录,以及 Web 服务器对该目录具有读写权限。

    1
    2
    3
    4
    5
    # 配置settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
    SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获 取一个临时地址tempfile.gettempdir()
    # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
    # 其他配置与db方式一致
  • 缓存+数据库:SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db’

    这种方案既保证快速存储会话数据,又保证数据持久性。因为该使用方案,Session 在保存到缓存的同时还会被保存到数据库中,当 Django 在缓存中找不到Session 时,会从数据库中找到。因此,这种方案的性能开销会比较大。

    如果我们在工程中同时配置了数据库会话和缓存会话,Django 默认优先选择缓存会话。

    1
    2
    3
    # 配置settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
    # 其他配置与db方式一
  • 加密 cookie:SESSION_ENGINE = ‘jango.contrib.sessions.backends.signed_cookies’

    这种方案将数据保存到 cookie 中。这种方案适用于对数据保密性不严格的场景。另外,建议增加配置SESSION_COOKIE_HTTPONLY= True,阻止 javascript 对会话数据的访问,提高安全性。

    1
    2
    3
    # 配置settings.py 
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
    # 其他配置与db方式一

Cookie常用方法:

常用方法 说明
set_cookie response.set_cookie(“cookie_key”,”value”) #设置Cookies
red.set_cookie(‘username’, u) #将用户名插入cookie
delete_cookie response.delete_cookie(“cookie_key”,path=”/“,domain=name)
删除Cookies
COOKIES value = request.COOKIES[“cookie_key”] # 获取Cookies
if “cookie_name” is request.COOKIES : # 检测Cookies
user = request.COOKIES.get(‘username’) #从cookie中取值
set_signed_cookie \rep.set_signed_cookie(key,value,salt=’加密盐’,…)
参数:
key, 键
value=’’, 值
max_age=None, 超时时间,表示多少秒数之后失效
expires=None, 超时时间,表示失效的时间点。支持datetime 和 time.time
path=’/‘, Cookie生效的路径,/ 表示根路径,特殊的:跟路 径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
secure=False, https传输
httponly=False 只能http协议传输,无法被JavaScript获取(不是 绝对,底层抓包可以获取到也可以被覆盖)

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。 <script src=’/static/js/jquery.cookie.js’></script>
$.cookie(“list_pager_num”, 30,{ path: ‘/‘ });
get_signed_cookie request.get_signed_cookie(key, default=RAISE_ERROR, salt=’’, max_age=None)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import render,redirect 
from django.shortcuts import HttpResponse
def login(request):
if request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
if u == 'alex' and p == '123':
red = redirect('/index/') #登录成功,则重定向到index
red.set_cookie('username', u) #将用户名插入cookie
return red
else:
return render(request, 'login.html')
else:
return render(request, 'login.html')

def index(request):
user = request.COOKIES.get('username') #从cookie中取值
if user:
return render(request, 'index.html', {'user':user})
else:
return redirect('/log/')

运行django之后,访问index,会自动跳转到login页面,输入账户密码之后,自动跳转到index,并从cookie中取出username,打印出来 。

**Session常用方法: **

常用方法 说明
request.session[‘k1’] 获取session,如果没有会报错
request.session.get(‘k1’,None) 获取session,如果没有会返回None
request.session[‘k1’] = 123 设置session,如果k1存在就覆盖
request.session.setdefault(‘k1’,123) 设置session,如果不存在则创建默认值,存在则不设置
del request.session[“k1”] 只删除k1,随机字符串和其他session值还存在
request.session.session_key 获取session字符串
request.session.clear_expired() 将所有Session失效日期小于当前日期的数据删除
request.session.exists(“session_key”) 检查用户session的随机字符串 在数据库中是否存在
request.session.delete(“session_key”) 删除当前用户的所有Session数据
request.session.clear() 清除用户的所有session数据,用于注销
request.session.set_expiry(value) 设置session超时时间,默认2周
# 如果value是个整数,session会在value秒后失效
# 如果value是个datatime或timedelta,session会在这个时间后失效
# 如果value是0,用户关闭游览器session会失效
# 如果value是None,session会依赖全局session失效策略
request.session.keys() 提取所有键
request.session.values() 提取所有值
request.session.iterkeys() 迭代键
request.session.itervalues() 迭代值
request.session.iteritems() 迭代键值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def session_login(request):
if request.method == 'POST':
user = request.POST.get('user')
pwd = request.POST.get('pwd')
if user == 'fuzj' and pwd == '123':
request.session['user'] = user
return redirect('/session_index/')
return render(request,'session_login.html')

@auth def session_index(request):
user = request.session.get('user',None)
return render(request,'index.html',{'user':user})

def session_logout(request):
del request.session['user']
return redirect('/session_login/')

测试点

会话生成

检查会话标识(sessionid)是否使用安全随机数算法生成,且有效长度不少于 24 个字 符(或 192bits);

如果使用 Django 内置的会话管理系统,会话标识符强且随机,可以无需测试。

会话超时

检查 settings.py 中会话相关的配置,是否设置了会话超时时间,超时过后必须要清除该会话信息;

超时时间根据业务进行设定,建议设置为 10 分钟。

正确的配置参考:

1
2
3
SESSION_COOKIE_AGE = 1209600     # Session的cookie失效日期(2周)(默认) 
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
会话固定

获取代码,搜索关键字“response.set_cookie”,检查用户成功登录后,系统是否更换会 话标识,重新设置了 sessionid,如果没有,则存在会话固定漏洞;

使用 Django 内置的会话管理系统,可以免受会话固定攻击。

安全属性配置

检查 settings.py 中 SESSION_ENGINE 的配置,是否设置了 PATH、DOMAIN、SECURE 和 HTTPONLY;其中,SECURE 和 HTTPONLY 必须设置为 True,其他根据实际业务进行设置:

1
2
3
4
SESSION_COOKIE_PATH = "/"       # Session的cookie保存的路径(默认) 
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = True # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输

设置了安全属性secure和httponly之后,能防止会话劫持,以及其他因无意使用HTTP发送敏感Cookie而造成的攻击。

会话保存

Django内部提供了5种类型的Session供开发者使用,通过在 settings.py 中增加 SESSION_ENGINE 配置实现。参考之前的介绍。

首先检查 settings.py 文件中 SESSION_ENGINE 的配置,判断使用了哪种方式保存 session 信息,如果使用 signed_cookies,则存在安全风险,建议整改;

会话加密传输

检查是否使用加密方式传输会话信息(建议使用 HTTPS,TLS 加密) ;

会话清除

找到 LOGOUT 接口,搜索关键字“request.session.delete(“session_key”)”,检查用户主动 退出时,服务器端是否清除该用户的会话信息;

检查会话超时后,系统是否主动清除用户的会话信息;

如果觉得写的还行,赞助瓶脉动~
0%