ASP.NET Core Razor Pages POST请求防篡改及特殊字符拦截问题
ASP.NET Core Razor Pages查询接口特殊字符绕过前端校验的成因与解决办法
问题描述
我开发了一个简单的ASP.NET Core Razor Pages站点,用户输入房间号即可查询其是否可用。提交至安全团队后收到反馈:POST请求存在漏洞,可通过原始或URL编码的特殊字符绕过前端校验。采取初步修复措施后,仍存在特殊字符(含空格%20)可通过URL编码或请求篡改绕过的问题,现咨询该问题的成因及解决办法。
相关代码片段
Index.cshtml(前端输入控件)
<input class="form-control" asp-for="InputRoomNo" pattern="[a-zA-Z0-9]+" title="Only charcters and letters please" minlength="3" maxlength="5">
Index.cshtml.cs(后端逻辑)
public class IndexModel : PageModel { public readonly IConfiguration config; [BindProperty(SupportsGet = false)] public string InputRoomNo { get; set; } public Room roomInfo = null; public string conn; public IndexModel(IConfiguration Configuration) { config = Configuration; } public void OnPost() { conn = config.GetConnectionString("ConnectionString"); string b = $"{InputRoomNo}"; b = Request.Form["inputRoomNo"]; roomInfo = Search($"{InputRoomNo}"); } public void OnGet() { } }
成因分析
- 前端校验无防御能力:前端的
pattern、minlength等规则仅用于引导普通用户输入,攻击者可直接通过工具(如Burp Suite、Postman)篡改HTTP请求,完全绕过前端校验,直接向后端发送带特殊字符的参数。 - 后端缺失输入校验:后端未对
InputRoomNo做任何合法性验证,直接将用户输入传入Search方法用于数据库查询。即便前端校验生效,后端也未形成二次校验的防线。 - URL编码字符未被过滤:ASP.NET Core会自动解码URL编码的字符(如
%20解码为空格),但后端未对解码后的内容做规则校验,导致解码后的特殊字符直接进入业务逻辑。 - 冗余代码存在风险:代码中
b = Request.Form["inputRoomNo"];直接读取原始表单数据,若后续逻辑误用该变量,会绕过模型绑定的校验逻辑,进一步扩大漏洞风险。
解决办法
1. 后端添加严格的输入校验(核心修复)
方式一:使用数据注解特性(简洁高效)
修改InputRoomNo的属性定义,通过注解实现校验规则:
[BindProperty(SupportsGet = false)] [RegularExpression(@"^[a-zA-Z0-9]{3,5}$", ErrorMessage = "房间号只能包含字母和数字,长度为3-5位")] [StringLength(5, MinimumLength = 3, ErrorMessage = "房间号长度必须在3-5位之间")] public string InputRoomNo { get; set; }
在OnPost方法中校验模型状态:
public void OnPost() { if (!ModelState.IsValid) { // 校验失败,返回页面显示错误提示 return; } conn = config.GetConnectionString("ConnectionString"); roomInfo = Search(InputRoomNo); }
方式二:手动正则校验(灵活可控)
在OnPost方法中添加正则校验逻辑:
public void OnPost() { var roomNoRegex = new System.Text.RegularExpressions.Regex(@"^[a-zA-Z0-9]{3,5}$"); if (string.IsNullOrEmpty(InputRoomNo) || !roomNoRegex.IsMatch(InputRoomNo)) { ModelState.AddModelError("InputRoomNo", "房间号只能包含字母和数字,长度为3-5位"); return; } conn = config.GetConnectionString("ConnectionString"); roomInfo = Search(InputRoomNo); }
2. 强制使用参数化查询(防止SQL注入)
Search方法用于数据库查询时,必须使用参数化查询而非字符串拼接,避免攻击者通过特殊字符构造恶意SQL语句。示例如下:
public Room Search(string roomNo) { using (var sqlConn = new SqlConnection(conn)) { sqlConn.Open(); // 参数化查询,将用户输入作为参数传入 var cmd = new SqlCommand("SELECT * FROM Rooms WHERE RoomNo = @RoomNo", sqlConn); cmd.Parameters.AddWithValue("@RoomNo", roomNo); // 执行查询并封装结果(示例逻辑) using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { return new Room { RoomNo = reader["RoomNo"].ToString(), IsAvailable = (bool)reader["IsAvailable"] }; } } } return null; }
3. 清理冗余代码
删除后端中无意义的string b = $"{InputRoomNo}"; b = Request.Form["inputRoomNo"];代码,避免后续逻辑误用原始表单数据导致校验绕过。
内容的提问来源于stack exchange,提问作者user10191234
相关产品推荐
相关产品推荐

