首页 / 资讯中心 / 文章详情

账号凭据只能放在本地,加密和失效检测该怎么设计才放心?

账号凭据只能放在本地,加密和失效检测该怎么设计才放心? ★ FEATURED ARTICLE
一、一份崩溃报告带出去半条会话今年年初有个客户反馈说他们的安全同事在一份崩溃报告里看到了登录态信息。这份报告是客户端异常退出时自动生成的包含调用栈、内存里几个关键对象的序列化内容还有最近一次请求的报文片段。问题在于我们当时为了排查方便把最近一次请求的完整头部也一起打进去了而头部里带着账号的会话凭据虽然报告只在本地生成但客户习惯把它导出上传给我们的支持同学凭据就这样跟着报告离开了这台机器。同一个月还出了另一件事。有个同事帮客户迁移环境把客户端配置整体导出一份发给对方导出内容包括账号列表、发布参数和运行偏好其中账号列表里顺手把会话数据也序列化进去了。那份文件被同事在几个工作群里转发了好几轮等我们发现的时候已经收不回来只能紧急要求相关账号全部重新登录。两次事故都不是加密算法出了问题而是我们从来没有认真界定过哪些字段属于凭据、它应该以什么形态离开内存。二、根子是把长期凭据当成了普通配置会话数据跟普通配置的区别在于时效和使用方式。一个账号的登录态通常能维持几天到几十天期间它可以代表这个账号完成发布、读取数据、修改设置等操作权限范围和密码几乎没有差别。这样一份东西如果明文写在磁盘文件里任何能读文件的进程都能拿走它而客户环境里能读文件的程序远比我们以为的多备份工具、杀毒软件、同步盘都在其中。第二个根子是边界没划。我们把账号相关的字段一股脑放在同一个结构里昵称、头像地址、平台标识、会话数据、刷新时间挤在一起于是日志打印、崩溃上报、配置导出这三条出口都很难只挑出安全的部分只要有一个地方用了整体序列化凭据就会跟着走。要解决这件事必须在数据结构层面就把凭据隔离出来让它在默认路径上根本不可见。第三个根子是失效判断依赖报错。早期版本的逻辑是等发布失败再提示用户重新登录结果是用户排了十篇稿子跑到第三篇才发现登录态早就过期前面两篇的产出还得人工处理。登录态的有效性应该主动探测而不是被动作业里撞出来这个判断成本很低一个轻量请求就能探明没理由把它留给故障去暴露。三、密钥从哪来是设计的核心第一条路是把密钥写进代码或者配置文件实现最省事跨机器也方便。代价是不能接受客户端程序一旦被反编译或者配置文件被复制所有机器上的凭据都能解开而且换密钥要发新版本等于没有回旋余地。我们试过用固定字符串加盐做简单混淆本质上和明文没有区别只是让人一眼看不出内容而已。第二条路是依赖操作系统的凭据存储把密钥交给系统托管的密钥库。这条路的安全性更靠得住系统会做访问控制代价是跨平台差异大部分环境里密钥库不可用或者需要额外授权部署和排障的复杂度都会往上走客户现场的运维同事未必能处理这类问题。我们把它作为可选的增强项不作为默认路径。第三条路是从机器特征派生密钥不落盘运行时算出来。机器特征取本机的主机名、系统安装标识和磁盘卷序列号三项用户级再加一个随机盐盐本身随数据一起存放它不需要保密。这条路的安全边界很清楚数据只在这台机器上、只在这个用户下可解复制走文件换台机器就解不开。我们选的是这条路并且把它作为默认实现。四、加密怎么写对称加密用 AES 二百五十六位的 GCM 模式它自带完整性校验密文被改动一位解密就会失败不需要额外挂一层摘要。每一次加密都生成一个随机的初始向量长度十二字节跟密文一起存认证标签十六字节也一起存。明文的形态是序列化后的会话结构加密之后写进一个单独的文件跟账号的其他字段分开存放账号索引文件里只留一个引用标识。密钥派生用 PBKDF2 加 SHA 二五六迭代十二万次输入是机器特征拼接用户级盐输出三十二字节作为数据加密密钥派生出来的密钥只在内存里存在。这套加密与失效检测是 AI智能媒体助理 账号管理里最不起眼但最不能省的一层。进程启动时派生一次之后常驻内存退出时不清洗内存里的密钥因为现代运行时的垃圾回收本来也不能确保擦除我们只能确保它不落盘、不进日志、不进任何导出。五、失效检测与日志脱敏失效检测走一个独立的巡检线程每六小时对每个账号发一个轻量请求只读一小段公开数据不做任何写操作。返回成功就刷新一次最近可用时间明确返回鉴权失败就把账号标成失效网络超时或者限流这类模糊结果按失败重试两次再判定避免把网络抖动误判成登录过期。失效的账号在列表里打上标记并提示重新登录发布队列在入队前先看这个标记失效的直接拦下不参与排队。日志脱敏落到了三个出口。运行日志里出现账号信息时只打印账号标识的后四位昵称和头像地址按需保留崩溃报告收集字段做白名单只允许调用栈、版本号、操作系统和错误码进入任何请求报文不进配置导出时按字段名单剔除凭据相关字段直接不出现在导出结构里导出的对象类型跟内存里的对象类型在代码层面就是两个不同的定义从类型上堵住误带的可能性。六、踩过的三个坑第一个坑是会话数据被写进崩溃报告。现象是客户反馈报告里能看到登录态片段根因是崩溃上报对整个上下文对象做了序列化而对象里带着请求头。改法有两条一条是把凭据从上下文中移出去放到一个不会被序列化的容器里另一条是把上报字段从黑名单改成白名单只有明确列出的字段才会进入报告。我们两条都做了因为黑名单这种思路在字段持续增加的时候一定会漏。第二个坑是多个进程同时写同一个会话文件导致互相覆盖。现象是客户端主程序、托盘小窗和后台更新程序同时运行一段时间后账号的登录态会随机退回上一版用户刚登录的账号过一会儿又提示要重新登录。根因是三方都持有这份文件并且各自写回后写的覆盖了先写的。改法是给文件加一把跨进程的排他锁写入按读取、修改、落盘的顺序完成锁的持有时间控制在几十毫秒内同时把不必要的写入路径收掉只允许主程序写凭据文件。第三个坑是导出配置文件时把凭据一起导出。现象是同事给客户的迁移包里带着账号登录态根因是导出直接序列化了内存里的账号对象。改法是定义一份专门给导出用的结构凭据字段根本不存在然后加一条开发期的断言凡是导出接口拿到的对象如果带凭据字段就直接抛错。这条断言拦下过两次后续新增字段带来的误带比事后再去补脱敏靠谱得多。七、这层解决不了什么加密解决的是文件被复制走的场景解决不了进程本身的权限问题。如果机器上已经运行着以同一用户身份执行的恶意程序它可以直接读我们的内存、调我们的接口加密在这种情况下只是增加了成本没有改变结论。所以真正需要隔离的环境还得配上系统级的账号隔离和权限收敛把风险从应用层拉到系统层去管别指望一层文件加密把所有问题都兜住。换机失效这个特性也不是所有人都欢迎。有客户做过机器快照按镜像批量部署到十几台设备上结果每台设备派生出来的密钥都一样因为机器特征相同这本来是我们预期外的行为。反过来客户更换硬盘或者重装系统之后凭据全部失效需要重新登录这个体验上的代价是我们主动选的换来的是文件被拷走也没有用取舍要在部署文档里写清楚。八、小结这套机制里没有复杂的技术AES 是老算法PBKDF2 也是标准件难的是承认凭据需要被区别对待并且在数据结构、日志、导出这三条出口上一处不漏地执行。我们后来做了一次回头看把凭据相关的处理集中在两个模块里其他任何地方都拿不到明文这条规矩比任何加密算法都更能防住事故。AI智能媒体助理 上账号凭据全部只留本地这台机器上的数据换台机器就解不开。这套做法上线之后客户安全同事再提同类问题时我们能拿出的答复是一份字段清单和一次现场演示而不是一句我们加密过了。回头看两年前那两份流出去的报告才是真正的起点它逼着我们把凭据当成一等公民对待这件事越早做越省事。
阅读完成 · 觉得有帮助?
咨询建站