SQL 注入示例

假设对 Web 应用程序的登录处理程序的调用如下所示:

https://somepage.com/ajax/login.ashx?username=admin&password=123

现在在 login.ashx 中,你可以阅读以下值:

strUserName = getHttpsRequestParameterString("username");
strPassword = getHttpsRequestParameterString("password");

并查询你的数据库以确定是否存在具有该密码的用户。

因此,你构造一个 SQL 查询字符串:

txtSQL = "SELECT * FROM Users WHERE username = '" + strUserName + "' AND password = '"+ strPassword +"'";

如果用户名和密码不包含引号,这将起作用。

但是,如果其中一个参数确实包含引号,则发送到数据库的 SQL 将如下所示:

-- strUserName = "d'Alambert";
txtSQL = "SELECT * FROM Users WHERE username = 'd'Alambert' AND password = '123'";

这将导致语法错误,因为 d'Alambertd 之后的引用结束了 SQL 字符串。

你可以通过转义用户名和密码中的引号来更正此问题,例如:

strUserName = strUserName.Replace("'", "''");
strPassword = strPassword.Replace("'", "''");

但是,使用参数更合适:

cmd.CommandText = "SELECT * FROM Users WHERE username = @username AND password = @password";

cmd.Parameters.Add("@username", strUserName);
cmd.Parameters.Add("@password", strPassword);

如果你不使用参数,并且忘记在其中一个值中替换引号,那么恶意用户(也称为黑客)可以使用它来在你的数据库上执行 SQL 命令。

例如,如果攻击者是邪恶的,他/她将设置密码

lol'; DROP DATABASE master; -- 

然后 SQL 将如下所示:

"SELECT * FROM Users WHERE username = 'somebody' AND password = 'lol'; DROP DATABASE master; --'";

不幸的是,这是有效的 SQL,DB 将执行此操作!

这种类型的漏洞被称为 SQL 注入。

恶意用户可以执行许多其他操作,例如窃取每个用户的电子邮件地址,窃取每个人的密码,窃取信用卡号,窃取数据库中的任何数据量等。

这就是为什么你总是需要转义你的字符串。
事实上你迟早会忘记这样做,这正是你应该使用参数的原因。因为如果你使用参数,那么你的编程语言框架将为你做任何必要的转义。