ASP中从同库多表检索用户凭据实现登录的问题排查
现有代码的核心问题
- 查询范围完全偏离需求:两段UNION子查询都只指向
student_regis表,完全没有关联Uni_regis表,压根没覆盖第二类用户的校验逻辑 - UNION使用逻辑错误:UNION会自动对结果集做去重,两个子查询分别返回单表的匹配计数,拼接后的结果会因为去重丢失统计准确性;同时
ExecuteScalar只会读取结果集第一行第一列的值,拿到的结果根本没法支撑校验判断 - 存在SQL注入风险:直接把前端输入的邮箱、密码字符串拼接到SQL语句中,没有做参数隔离,很容易被恶意篡改查询逻辑,甚至拖取全表数据
- 校验判断逻辑不合理:只要存在任意一条匹配的账号密码记录就应该允许登录,不需要严格匹配计数等于1
修正实现代码
正确的逻辑应该是先汇总两张表中匹配的凭据记录,再统计总匹配数,通过参数化查询避免注入风险,参考实现如下:
protected void Button1_Click(object sender, EventArgs e) { // 汇总两张表的匹配记录总条数 String query = @"SELECT COUNT(*) FROM ( SELECT email FROM student_regis WHERE email = @Email AND password = @Pwd UNION ALL SELECT email FROM Uni_regis WHERE email = @Email AND password = @Pwd ) AS MatchRecords"; // 确保数据库连接处于打开状态 if (scon.State == System.Data.ConnectionState.Closed) { scon.Open(); } SqlCommand cmd = new SqlCommand(query, scon); // 以参数形式传入输入内容,避免SQL注入 cmd.Parameters.AddWithValue("@Email", mail.Text.Trim()); cmd.Parameters.AddWithValue("@Pwd", password.Text.Trim()); int matchResult = Convert.ToInt32(cmd.ExecuteScalar()); scon.Close(); // 存在任意一条匹配记录即判定身份校验通过 if (matchResult > 0) { Response.Redirect("~/Home_page.aspx"); } else { Response.Write("Username or password was wrong"); } }
实现注意事项
- 跨表统计时优先用UNION ALL代替UNION:我们不需要对两表的匹配记录做去重,UNION ALL执行效率更高,不会因为去重逻辑额外消耗数据库性能
- 所有用户输入必须通过参数化查询方式传入SQL,不能直接拼接字符串:既可以杜绝SQL注入风险,也能避免因为输入内容包含单引号等特殊字符导致的查询语法报错
- 直接把查询返回的计数转为整数做大小判断,不需要转成字符串再做等值比较,减少类型转换带来的不必要异常
内容的提问来源于stack exchange,提问作者Jay Modi
相关产品推荐
相关产品推荐

