ASP.NET Core应用整数溢出问询:分页乘法是否存在溢出风险
ASP.NET Core分页代码中的整数溢出风险分析
核心结论
会引发整数溢出漏洞,你代码里intSkip * intTake的乘法操作确实存在安全风险,以下是具体分析和修复方案:
风险原因
.NET中的int是32位有符号整数,取值范围为-2147483648到2147483647。当查询字符串传入的pageNo和itemsPerPage都是较大的正整数时,两者的乘积很容易超出int的最大值,触发整数溢出:
- 比如
pageNo=50000、itemsPerPage=50000,乘积为2500000000,已经超过int的最大值; - .NET默认不会对有符号整数溢出抛出异常,溢出后的结果会变成错误的负数或小正数;
- 错误的
skip值传给EF Core的Skip方法后,要么抛出参数非法异常,要么导致分页逻辑完全失效(比如返回空数据、跳过条目数远低于预期)。
修复方案
1. 强制溢出检查
用checked块包裹乘法操作,溢出时直接抛出异常,提前拦截非法输入:
[HttpGet] public async Task<IActionResult> GetAllBooksAsync([FromQuery] string pageNo, string itemsPerPage) { int intSkip = int.TryParse(pageNo, out int _skip) ? _skip : 0; int intTake = int.TryParse(itemsPerPage, out int _take) ? _take : 0; int skip; try { checked { skip = intSkip * intTake; } } catch (OverflowException) { return BadRequest("分页参数过大,请传入合理的页码和每页条目数"); } var result = await _repo.GetAllBooksAsync(skip, intTake); return Ok(result); }
2. 限制参数范围
直接对pageNo和itemsPerPage的取值做上限限制,从源头避免乘积溢出:
[HttpGet] public async Task<IActionResult> GetAllBooksAsync([FromQuery] string pageNo, string itemsPerPage) { // 根据业务需求调整上限,比如页码最大10000,每页条目数最大1000 int intSkip = int.TryParse(pageNo, out int _skip) ? Math.Clamp(_skip, 0, 10000) : 0; int intTake = int.TryParse(itemsPerPage, out int _take) ? Math.Clamp(_take, 0, 1000) : 0; var result = await _repo.GetAllBooksAsync(intSkip * intTake, intTake); return Ok(result); }
3. 使用更大的数据类型
将分页计算变量改为long(64位整数),扩大取值范围避免溢出:
- 控制器方法修改:
[HttpGet] public async Task<IActionResult> GetAllBooksAsync([FromQuery] string pageNo, string itemsPerPage) { long longSkip = long.TryParse(pageNo, out long _skip) ? _skip : 0; int intTake = int.TryParse(itemsPerPage, out int _take) ? _take : 0; long skip = longSkip * intTake; var result = await _repo.GetAllBooksAsync(skip, intTake); return Ok(result); }
- 仓储方法修改:
public async Task<IEnumerable<Book>> GetAllBooksAsync(long skip = 0, int take = 0) { var query = _ctx.Books.Skip((int)skip); // 若skip可能超过int范围,可直接用Skip(skip),EF Core支持long类型的Skip参数 if(take < 1) { return await query.ToListAsync(); } return await query.Take(take).ToListAsync(); }
额外优化:修正分页逻辑
通常分页页码从1开始,当前代码中pageNo=1时会跳过第一页所有数据,建议调整为:
skip = (intSkip - 1) * intTake;
同时注意处理intSkip为0的情况,避免出现负数skip值。
内容的提问来源于stack exchange,提问作者Zombies are Real
相关产品推荐
相关产品推荐

