把认证、授权与数据过滤拆成三道边界
认证回答请求者是谁,授权回答这个身份能否执行某个动作,数据过滤决定允许看到哪些字段和记录。Nuxt 页面中只检查存在登录会话,不能替代服务端对文章删除、后台统计或私人草稿读取的授权。浏览器中的路由中间件主要改善跳转体验,它运行在用户可控制的环境,任何敏感服务器接口都必须独立验证身份和权限。
服务端处理程序应从受信请求上下文取得已经验证的主体,而不是接受正文中的用户编号或角色。资源型操作还要检查主体与资源关系,例如作者只能编辑自己的草稿,管理员可以审核但未必能读取账户机密字段。把“已登录”当成全站通行证,会让横向越权隐藏在正常的二百响应里。
访问决策应尽量靠近数据读取和写入处。页面先获取全部对象再在客户端删掉敏感字段,秘密已经进入页面负载和网络响应;通用仓储无条件查询后由调用者过滤,也容易有一个新入口忘记调用过滤器。查询条件直接包含租户、所有者、发布状态和作用域,并让选择字段列表只包含当前用途所需内容。
会话解析只信任签名与服务端状态
Cookie 中的会话标识必须使用安全属性并在服务端验证签名、过期时间和预期用途。即使令牌包含角色,权限撤销、密码重置或强制下线也可能要求查询服务端会话版本;只验证令牌密码学有效会继续接受旧权限。会话版本、用户禁用状态和关键权限变更应参与每次敏感操作的判定或经过有界缓存。
不要从客户端可写 Cookie、查询参数或请求头直接读取角色。代理转发身份头时,应用只应在已知反向代理清除了外部同名头并重新注入的拓扑中信任它,否则公网请求可以自行伪造。部署测试要绕过常规页面直接调用接口,并验证来自外部的身份相关头会被忽略或拒绝。
服务端渲染期间获取当前用户时,要使用当前请求的 Cookie 和事件上下文,不能把主体放进模块级变量。常驻进程会并发处理不同用户,一个全局可变身份可能将甲的权限带入乙的渲染。并发测试同时发送两组会话,反复读取个性化页面与接口,可以捕获顺序执行测试看不到的跨请求污染。
页面中间件只负责体验层导航
路由中间件可在进入后台前调用会话接口,根据未登录、权限不足和过期状态导航到合适页面,并保存经过校验的站内返回地址。它能避免用户先看到后台骨架再失败,但不能成为唯一门禁,因为接口可被脚本直接访问,服务端渲染路径也可能与客户端导航执行时机不同。真正的拒绝仍由每个服务端端点完成。
通用中间件要避免在服务端渲染会话页时再次请求自身公网地址造成额外跳转或 Cookie 丢失。可以在服务端直接读取事件上下文的会话能力,在客户端导航时调用会话端点,并让两者返回同一规范主体形状。若采用数据缓存,请求键必须按会话隔离,不能让匿名结果覆盖登录结果或反向泄露。
登录页、退出端点和权限不足页需要明确排除保护中间件,否则会形成重定向循环。返回地址只能接受同源相对路径,拒绝协议开头、双斜线和编码后逃逸形式,避免登录后开放重定向。测试应限制最大跳转次数,并覆盖会话刚好过期、用户角色刚被撤销以及浏览器后退缓存恢复页面的情况。
服务端端点采用拒绝优先的固定顺序
端点处理顺序可以固定为解析会话、验证有效状态、检查动作权限、验证输入、按授权范围查询资源、执行变更和记录审计。资源不存在与无权查看有时统一返回未找到,避免泄露私人标识是否存在;后台管理端则可在不扩大信息泄露的前提下区分权限不足。选择要写入接口契约,而不是由每个处理程序随意决定。
授权检查不能只依赖客户端先前读取到的对象版本。更新和删除时在数据库条件中同时加入资源标识、所有者或租户和版本,受影响行数为零时再区分冲突与不可见。先查权限、隔很久后无条件更新会留下检查与使用之间的窗口,资源所有者或状态在窗口内变化就可能越过最新决策。
批量操作尤其容易漏边界。不能只检查第一条记录或要求“列表里至少一条属于我”,应保证每条目标都在授权集合内,或者在单条原子查询中只更新允许范围并核对数量。部分成功是否允许必须明确;若允许,逐项返回不泄密的结果,若不允许则在事务中全部拒绝。
页面负载与错误不能泄露隐私
Nuxt 的服务端数据会序列化到浏览器供水合复用,因此从服务器取得的对象并非天然私密。数据库用户模型中的密码摘要、会话版本、内部风控标记和恢复凭据不应进入页面数据,即使模板没有显示它们。为公开资料、本人账户和管理员视图分别定义输出形状,从查询选择阶段就排除无关字段。
错误响应不要包含数据库语句、令牌、Cookie、请求正文或完整内部堆栈。客户端需要稳定的状态码、可公开错误码和脱敏请求标识;服务端日志用该标识关联详细异常,并仅记录方法、规范路径、状态与必要主体编号。路径中若含敏感查询,应记录路由模板而非原始地址,日志采集也要设置保留期和访问控制。
缓存是另一条泄露路径。包含个人信息或权限差异的响应默认设为私有或不缓存,不能只靠缓存键里的一个用户编号期待边缘设施正确理解。若确实缓存授权结果,键必须覆盖主体权限版本和资源作用域,并在撤权时失效。共享缓存页面只包含所有访问者完全相同的公开数据。
跨站请求与令牌传递各有防线
基于 Cookie 的会话会被浏览器自动附加,因此改变状态的请求需要同站属性、来源校验和防跨站请求伪造机制。只要求自定义请求头可以阻挡普通表单,但还要正确处理允许的同源请求、内容类型和跨域预检。读取端点也不应无条件认为安全,如果它会触发发信、生成一次性凭据或改变最后访问状态,仍应按变更操作保护。
承载令牌的授权头不会由浏览器自动发送到第三方,但令牌更容易被前端脚本和存储泄露。不要把长期令牌放在本地存储作为默认会话方案,也不要把它拼进地址。服务端代理调用下游时只转发该下游需要的最小凭据,禁止将入站全部头原样透传到任意用户提供的网址。
跨域配置必须列出可信来源,携带凭据时不能使用任意来源通配。来源匹配按规范化的协议、主机和端口进行,不能用字符串后缀接受伪造域名。验证矩阵包括缺失来源、伪造子域、不同端口、预检请求、简单表单和带凭据获取,确认拒绝发生在业务变更之前。
用角色、资源与渲染方式组成测试矩阵
权限测试至少包含匿名用户、普通用户、资源所有者、同租户非所有者、其他租户用户、过期管理员和有效管理员。对每个读取、创建、更新、删除及批量动作直接调用服务端端点,不经过页面中间件,断言状态码、返回字段和数据库副作用。尤其要比较存在但不可见的资源与随机标识,避免响应时间或消息暴露存在性。
渲染矩阵覆盖服务端首次打开、客户端路由进入、刷新、后退恢复和会话在页面停留期间过期。服务端 HTML 与水合负载都不得包含禁止字段;权限撤销后下一次敏感请求必须失败,客户端清除旧私密数据并引导重新验证。并发不同主体请求时检查缓存头、请求键和页面内容没有串用户。
故障注入包含会话存储不可用、数据库权限查询超时、审计日志暂时失败和代理丢失身份上下文。安全决策依赖不可用时应拒绝敏感操作,不能降级为匿名可读或沿用过期管理员结果。审计写入是否与业务事务绑定要事先决定并测试;无论策略如何,告警都应携带脱敏请求标识,使运维可以复原一次拒绝或变更的决策链。
实现片段
const admin = await requireAdmin(event)
评论 · 0