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'";

这将导致语法错误,因为din后面的引号d'Alambert以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,数据库将执行此操作!

这种利用方式称为SQL注入。

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

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