网站数据分页漏洞的实质,是服务端把本应通过权限校验或数据脱敏才能获取的记录,错误地暴露在了可遍历的页码、ID或排序参数中。攻击者不需要掌握任何高级渗透技巧,只要在浏览器地址栏修改page、limit、id、order等参数,就能批量拉取未授权数据。很多开发者认为分页只是前端展示逻辑,却忽略了每一次翻页请求都等于一次数据库查询授权。分页参数一旦失去服务端约束,就等同于把数据库大门敞开了一半。

最常见的风险场景是越权遍历。比如用户A登录后查看自己的订单列表,URL为/order/list?page=1,服务端根据session中的用户ID查询数据,这本身没有问题。但如果接口同时接收user_id参数,并且后端优先使用传入的user_id而非session值,攻击者就能通过修改user_id和page参数,逐页拉取其他用户的订单。更隐蔽的情况是,某些报表接口为了“方便内部调用”,在测试环境关闭了权限校验,上线时忘记恢复,分页参数pageNum和pageSize就成了批量导出的工具。

另一种高发漏洞是分页参数缺乏上限控制。例如接口允许pageSize=10000,攻击者一次请求就能把整张表拖走。即使默认每页20条,只要page参数没有上限校验,攻击者写个简单脚本从page=1循环到page=99999,照样能把全量数据爬完。很多企业以为做了登录校验就安全了,实际上登录后的水平越权才是数据泄露的重灾区。分页漏洞往往不是孤立存在的,它经常和IDOR(不安全的直接对象引用)、缺失的速率限制、过度暴露的字段等问题叠加出现。

要彻底规避分页漏洞,首先必须明确一个原则:分页参数只控制返回数据的“窗口”,绝不控制“数据范围”。数据范围必须由服务端根据当前用户的身份、角色、租户、部门等上下文强制限定。任何来自客户端的过滤条件,比如user_id、dept_id、company_id,都必须经过服务端校验,确认当前用户有权访问该范围内的数据。最稳妥的做法是,服务端在构造查询条件时,完全忽略客户端传入的归属类字段,只使用session或token中可信的身份信息。

具体到代码层面,假设你有一个订单查询接口,错误写法是直接把前端传入的userId拼进SQL:

-- 危险示例:前端传入userId,后端直接使用
SELECT * FROM orders WHERE user_id = #{userId} LIMIT #{offset}, #{pageSize}

正确做法是后端从安全上下文中获取当前用户ID,并且校验请求参数中是否包含越权字段。如果业务确实需要管理员按用户筛选,那必须单独做角色校验,确认当前用户具备管理员权限,同时对筛选的用户ID做存在性和归属范围校验。普通用户查询自己的订单时,SQL应该固定为:

-- 安全示例:用户ID从服务端会话获取
SELECT * FROM orders WHERE user_id = #{currentUserId} LIMIT #{offset}, #{pageSize}

分页参数本身也需要严格校验。page和pageSize必须是正整数,pageSize必须有最大值限制,通常建议不超过100,特殊报表场景需要更大值时,必须走单独的导出接口并增加审批或审计。page参数要防止整数溢出,比如传入超大数字导致计算offset时溢出为负数,从而绕过限制。服务端在计算offset时,应该使用长整型并检查是否超过合理范围。同时要限制最大可访问页码,比如当数据总量为1000条、每页20条时,page最大只能是50,超过50直接返回空列表或错误提示,而不是继续查询数据库。

排序参数order和sort也是分页漏洞的常见入口。很多开发者为了灵活,允许前端传入任意字段名作为排序依据,攻击者可以通过order=password或order=secret_key来探测表结构,甚至配合报错信息推断字段类型。正确做法是维护一个允许排序字段的白名单,前端只能传白名单内的字段名,服务端做映射后再拼入SQL。任何不在白名单中的字段,直接忽略或返回参数错误。

数据脱敏是分页防护的最后一道防线。即使前面的权限校验被绕过,如果返回的数据中敏感字段已经脱敏,损失也能降到最低。比如手机号显示为1385678,身份证号只显示前6位和后4位,银行卡号只显示后四位。脱敏必须在服务端完成,绝不能依赖前端隐藏。很多前端只是用CSS或JS把敏感字段遮住,查看接口响应时明文依然可见。服务端脱敏可以统一在序列化层做,根据字段类型和当前用户权限动态决定返回明文还是掩码。

分页接口还应该增加速率限制和异常行为检测。正常用户翻页速度有限,而爬虫脚本往往在短时间内请求大量不同页码。可以在网关层或应用层对分页接口做限流,比如同一用户每分钟最多请求60次翻页。同时记录分页请求日志,当某个用户短时间内的翻页次数、请求的数据范围出现异常时触发告警。日志中要记录用户ID、请求参数、返回条数、时间戳,便于事后审计和溯源。

对于已经存在分页漏洞的系统,修复时要特别注意兼容性问题。直接强制pageSize上限可能导致部分前端页面报错,需要提前通知前端团队调整调用逻辑。修复越权漏洞时,要确认所有调用方都不再依赖传入的归属类字段,否则可能影响正常业务。建议先在测试环境验证修复方案,再灰度发布到生产环境。修复完成后,还要对历史日志进行排查,确认漏洞是否已经被利用,评估数据泄露的范围和影响。

一个容易被忽视的细节是,分页漏洞不仅存在于Web接口,也存在于API接口、小程序后端、移动端接口。很多企业只关注网页端的安全,却忘了小程序和App调用的API同样存在分页参数。攻击者完全可以直接抓取App的接口请求,修改参数后重放。因此安全策略必须覆盖所有对外提供服务的接口,包括内部服务之间通过HTTP调用的接口。内部接口如果暴露在办公网中,同样可能被恶意员工或入侵者利用。

从架构层面看,分页查询应该尽量使用服务端游标或加密游标,而不是简单的页码偏移。页码偏移在数据变动时容易出现重复或遗漏,而游标机制可以保证翻页的稳定性。加密游标还能防止攻击者猜测或篡改游标值,比如使用AES加密的游标字符串,服务端解密后校验合法性。对于数据量巨大的表,页码偏移的性能也很差,深分页会导致数据库扫描大量无用数据。使用游标或基于索引的条件查询,既能提升性能,又能降低被遍历的风险。

还有一个常见误区是认为数据量小就不需要防护。实际上,哪怕一张表只有几百条记录,一旦包含手机号、身份证、银行卡、地址等敏感信息,被遍历的后果同样严重。数据泄露的价值不在于数据量大小,而在于数据的敏感程度和精准度。攻击者拿到几百条真实用户信息,足以发起精准诈骗。所以分页防护不分数据量大小,只要接口返回的数据包含个人信息或商业敏感信息,就必须落实权限校验、参数限制和脱敏措施。

在安全测试中,分页漏洞的检测方法很直接。登录一个普通用户账号,找到所有带分页参数的接口,依次修改page、pageSize、userId、deptId等参数,观察返回数据是否超出了当前用户应有的范围。特别注意那些返回了其他用户数据的接口,以及pageSize设置为超大值时是否返回全量数据。测试时可以使用浏览器开发者工具或Postman等工具,记录每个接口的响应内容,对比不同参数下的数据差异。自动化扫描工具也能辅助发现这类问题,但最终确认还需要人工判断返回数据是否越权。

对于开发团队来说,建立统一的分页查询规范比事后修补更重要。规范中应明确:分页参数必须经过校验,pageSize有默认值和最大值,page有上限控制;排序字段必须走白名单;归属类字段一律从服务端会话获取,不信任客户端传入;所有分页接口必须经过权限校验,权限校验逻辑放在业务查询之前;敏感字段必须在服务端脱敏;分页接口必须记录访问日志并设置速率限制。这套规范要落实到代码评审和上线检查中,而不是停留在文档里。

数据分页漏洞的防护不是一次性工作,而是持续的过程。新功能上线、接口改造、第三方系统对接,都可能引入新的分页风险。安全团队应该定期对核心业务接口进行分页安全巡检,结合日志分析发现异常遍历行为。开发人员在编写每一个分页查询时,都要问自己三个问题:数据范围是否由服务端控制?分页参数是否经过严格校验?返回的数据是否包含未脱敏的敏感信息?只有把这三个问题变成肌肉记忆,才能真正规避分页漏洞导致的信息泄露。