什么是sql注入及应对办法
举个栗子:
这是前端登录页面,有2个输入框,一个账号,一个密码,一个提交按钮
<input type="text" name="account" placeholder="请输入账号" />
<input type="text" name="password" placeholder="请输入密码" />
<button>登录</button>
这是后端代码,以C#举例,接收前端传过来的账号和密码,进行登录验证
public void Login(string account, string password)
{
//拼接sql语句,根据账号密码到用户表user查询用户
var sql = $"select top 1 * from user where account ='{account}' and password ='{password}' ";
//执行sql
var user = db.Excute(sql);
if(user == null)
{
//登录失败,前端提示用户:账号或者密码不正确
}
else
{
//登录成功
}
}
有一个用户叫张三,账号是:zhangsan,密码是:666
正常流程:张三在前端页面输入自己的账号 zhangsan 和密码 666,点击登录按钮,后端拼接出的sql就是:
select top 1 * from user where account ='zhangsan' and password ='666'
然后张三就成功登录进系统了对吧。
好了,非正常流程来了:
张三通过某种不可描述的方式知道了李四的账号是 lisi,但是不知道密码。
于是张三在前端页面上的骚操作来了,他在账号输入框里输入 lisi,在密码输入框里输入 1’ or 1=1,点击登录按钮。
于是,提交到后端后拼接出的sql就变成了这样:
select top 1 * from user where account ='lisi' and password ='1' or 1=1
于是,他登录成功了!
甚至,张三恶向胆边生,在密码输入框里输入了 1’; drop table user;
好了,现在你明白了,这玩意儿就叫sql注入!
听懂掌声!
听不懂自己写代码试一下!
应对办法:
- sql语句可以写,但是前端输入的值不要以拼接字符串的方式直接拼接到查询语句中。
- 写后端代码的同学记住一句话:永远不要相信前端传过来的数据。
- 你不知道某些奇葩用户会输入一个什么东西传过来,所以哪怕前端做了校验,但那不关你的事,你就当前端没校验,你后端该做的校验一个都不能少。
//先对传入的值做合法性校验。
//...
//拼接sql语句
var sql = $"select top 1 * from user where account=@account and password=@password";
var paras = new Dictionary<string, dynamic>();
paras.Add("account", account);
paras.Add("password", password);
//执行sql
var user = db.Excute(sql, paras);
//db帮助类相关代码:
Excute(System.Data.Common.DbConnection con, System.Data.CommandType commandType, string commandText, Dictionary<string, dynamic> paras = null)
{
try
{
con.Open();
using var cmd = con.CreateCommand();
cmd.CommandText = commandText;
cmd.CommandType = commandType;
//遍历传进来的paras字典,添加到cmd参数中
foreach (var par in paras)
{
var parameter = cmd.CreateParameter();
parameter.ParameterName = par.Key;
parameter.Value = par.Value;
cmd.Parameters.Add(parameter);
}
查询条件拼接有时候不一定是等号,有时候会查询某个字段大于某个值,或者包含某个值等,大于 >、小于 < 用法和 等号是一样的,但是包含 like 和 in 特殊点,用法看这篇:
sql 查询条件 like 和 in 参数化写法