开篇故事:一张永远有效的“万能门票”
某在线教育平台的学员小王收到一封“课程优惠券”邮件,点击链接后正常登录账户。
一周后,小王发现自己的VIP课程被陌生人观看,学习记录中出现不明设备登录。
真相:攻击者通过邮件链接植入“固定会话ID”,如同复制了小王的账户。
一、会话管理基础:为什么需要“会话ID”?1. 会话机制的本质
一般来说,当用户访问一个网站时,服务器会为每个用户创建一个会话,无论用户是否登录。这个会话ID通常是在用户第一次访问网站时生成的,用于跟踪用户的状态。
例如,未登录的用户可能将商品添加到购物车,这时候服务器需要维护一个会话session超时,所以即使未登录,也会分配会话ID。这种情况下,登录前的会话ID是存在的,但权限较低,仅用于临时状态保存。
2. 正常会话流程
用户首次访问:
客户端后续请求:
用户登录:
关键点:
二、会话固定攻击原理:攻击者如何“复制钥匙”?1. 攻击四步走
生成固定会话ID:攻击者访问网站,获取特定会话ID(如=abcd)
诱导用户使用该ID:通过邮件/钓鱼页面发送含=abcd的链接
用户登录绑定会话:用户点击链接登录,服务器将账户与abcd关联
攻击者接管会话:攻击者使用abcd访问网站session超时,直接获得用户权限
2. 漏洞代码示例(危险!)
// 错误示例:允许通过URL参数指定会话ID
if(isset($_GET['sessid'])) {
session_id($_GET['sessid']); // 接受外部传入的会话ID
}
session_start();
// 用户登录后未重置会话ID
if($login_success) {
$_SESSION['user'] = $username;
}
攻击:
https://example.com/login.php?sessid=abcd
三、真实案例:血淋淋的教训案例1:某银行转账功能沦陷案例2:政府OA系统公文泄露四、防御指南:四道防线锁死会话安全防线1:登录时强制生成新会话ID
// 正确示例:登录成功后重置会话ID
session_start();
if($login_success) {
session_regenerate_id(true); // 销毁旧会话,生成新ID
$_SESSION['user'] = $username;
}
原理:
防线2:会话ID绑定多因素
# Django示例:会话ID绑定IP+UserAgent
from django.contrib.sessions.backends.db import SessionStore
def create_session(request):
s = SessionStore()
s['ip'] = request.META['REMOTE_ADDR']
s['ua'] = request.META['HTTP_USER_AGENT']
s.save()
return s.session_key
验证逻辑:
if request.session['ip'] != current_ip:
logout_user()
防线3:严格传输安全策略
# 响应头设置(防止会话ID被嗅探)
Set-Cookie: PHPSESSID=abcd1234; Secure; HttpOnly; SameSite=Strict
若想了解CSRF的漏洞原理,可以参阅。
防线4:主动销毁过期会话
// Spring Security配置会话超时
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.invalidSessionUrl("/login?expired") // 会话失效跳转
.maximumSessions(1) // 最大会话数
.maxSessionsPreventsLogin(true) // 阻止新登录
.expiredUrl("/login?expired"); // 会话过期跳转
}
}
策略:
五、实战演练:手把手检测你的网站
检测步骤:
1、访问网站:通过F12查看登录前中的会话ID
2、观察登录后响应:若生成新ID如=→ 防御生效
自动化工具推荐:
限时特惠:本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情
站长微信:Jiucxh