You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC项目Session加载用户数据偶发串号查看他人数据问题咨询

问题核心原因

你遇到的跨用户数据泄露问题,是几个典型的编码缺陷共同造成的,其中几个触发点完全能对应你说的「隔几个月偶发」的特征:

  • Session丢失直接导致查询条件失效
    你完全依赖Session["id"]存储当前用户的FormId,但ASP.NET MVC默认使用进程内(InProc)Session存储,只要出现应用池定期/异常回收、站点配置文件改动、bin目录文件更新、服务器内存占用过高等情况,进程内存里存储的Session数据会被全部清空。此时var tosee = (string)Session["id"]会取到null,你的查询逻辑会变成db.WorkExps.Where(x => x.FormId == null).ToList()——只要数据库里存在FormId字段为null的历史申请数据,这些数据会被全量返回给当前用户,直接出现看到其他人数据的情况。
    另外如果用户在同一个浏览器下打开多个申请标签页,后打开的页面会覆盖Session["id"]的值,用户回到之前打开的标签页滚动加载时,就会拉取到新标签页对应的申请数据,也会触发串号。
  • DbContext使用不当引发线程安全问题
    如果你把EF的DbContext声明为全局静态实例、或者在依赖注入容器里注册成单例生命周期,会直接触发线程安全问题。DbContext本身设计为单请求单实例使用,多并发请求复用同一个DbContext时,内部的跟踪缓存、查询状态会出现串扰,A用户的查询结果可能被直接返回给B用户,这类问题的触发没有固定规律,完全符合偶发故障的特征。
  • 接口完全缺失边界校验逻辑
    你的所有数据查询接口都只靠Session里存储的id做匹配,既没有判断Session值是否为空,也没有校验查询到的数据是否属于当前用户,只要Session值丢失、被覆盖、被污染,查询逻辑就会越权返回不属于当前用户的数据。

另外你写的FormId生成逻辑也存在冗余风险:用db.Applicants.Count()拼前缀的写法在高并发场景下可能拿到重复值,实际上直接用Guid作为FormId已经完全能保证全局唯一,不需要额外拼接表记录总数,多余的Count查询反而会增加数据库压力。

修复方案
  • 调整DbContext生命周期为请求级别,每次请求新建DbContext实例,请求结束后释放,禁止全局复用DbContext。
  • 调整FormId的存储和传递逻辑:页面加载生成FormId后,除了Session存储之外,把值直接写入页面隐藏域,前端加载表格数据时把FormId作为参数传给后端接口,后端查询前必须校验传入的FormId格式合法性,如果站点有登录体系,还要额外校验FormId对应的申请是否属于当前登录用户。
  • 所有查询执行前必须加非空判断:如果取到的FormId为空、格式非法,直接返回空结果或者重定向到表单首页,绝对不允许执行x.FormId == null这类全量匹配空值的查询。
  • 如果要继续使用Session做状态存储,把Session存储模式从默认的InProc改成StateServer或SQLServer模式,避免应用池回收导致的Session批量丢失。
  • 简化FormId生成逻辑,去掉Count()拼接逻辑,直接使用Guid作为FormId即可。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 02:57:33