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'Alambert
中 d
之后的引用结束了 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 注入。
恶意用户可以执行许多其他操作,例如窃取每个用户的电子邮件地址,窃取每个人的密码,窃取信用卡号,窃取数据库中的任何数据量等。
这就是为什么你总是需要转义你的字符串。
事实上你迟早会忘记这样做,这正是你应该使用参数的原因。因为如果你使用参数,那么你的编程语言框架将为你做任何必要的转义。