这个MySQL查询如何容易受到SQL注入的攻击?

这个MySQL查询如何容易受到SQL注入的攻击?,mysql,security,sql-injection,Mysql,Security,Sql Injection,在对上一个问题的评论中,有人说下面的sql语句为我打开了sql注入的大门: select ss.*, se.name as engine, ss.last_run_at + interval ss.refresh_frequency day as next_run_at, se.logo_name from searches ss join search_engines se on ss.engine_id = se.id where s

在对上一个问题的评论中,有人说下面的sql语句为我打开了sql注入的大门:

select
    ss.*,
    se.name as engine,
    ss.last_run_at + interval ss.refresh_frequency day as next_run_at,
    se.logo_name    
from 
    searches ss join search_engines se on ss.engine_id = se.id
where
    ss.user_id='.$user_id.'
group by ss.id
order by ss.project_id, ss.domain, ss.keywords

假设
$userid
变量已正确转义,这如何使我易受攻击,我可以做些什么来修复它?

假设它已正确转义,则不会使您易受攻击。问题是,正确地逃脱比乍一看要困难得多,每次你做这样的查询时,你都会责怪自己要正确地逃脱。如果可能,避免所有这些麻烦,并使用准备好的语句(或绑定参数或参数化查询)。其思想是允许数据访问库正确地转义值

例如,在PHP中,使用:


每一个值得使用的SQL接口库都支持绑定参数。不要试图变得聪明,只要运用它

你可能真的,真的认为/希望你已经正确地逃离了这些东西,但这不值得你花那么多时间

另外,一些数据库支持预处理语句缓存,因此正确地进行预处理也可以提高效率


更简单、更安全、更快。

这句话本身并不是什么问题,它是“安全的”,但我不知道您是如何做到这一点的(API堆栈上的一级)。如果使用字符串操作将$user_id插入到语句中(就像让Php自动填充语句一样),那么它是危险的


如果它是使用绑定API填充的,那么您就可以开始了。

如果它被正确转义和验证,那么您就没有问题了

如果未正确转义或验证,则会出现问题。这可能是由于编码马虎或疏忽造成的


问题不在于特定的实例,而在于模式。此模式使SQL注入成为可能,而另一种模式则使之不可能。

如果转义了$user\u id,则您不应受到SQL注入的攻击


在本例中,我还将确保$user_id是数字或整数(取决于所需的确切类型)您应该始终将数据限制在最严格的类型。

所有答案都是正确的,但我觉得我需要补充的是,
准备
/
执行
范例也不是唯一的解决方案。你应该有一个数据库抽象层,而不是直接使用库函数,这样一个层是显式转义字符串参数的好地方,不管你是让
准备
还是你自己做。

我认为“正确转义”是关键词。在您的示例中,我假设您的代码是从生产代码复制粘贴的,并且由于您询问了有关三个表联接的问题,我也假设您没有进行正确的转义,因此我对SQL注入攻击发表了评论


为了回答您的问题,正如这里很多人所描述的,如果变量已“正确转义”,则您没有问题。但是为什么要这样做来麻烦你自己呢?正如一些人指出的那样,有时适当地逃离并不是一件简单的事情。PHP中有一些模式和库使得SQL注入变得不可能,我们为什么不直接使用它们呢?(我还特意假设您的代码实际上是PHP)。Vinko Vrsalovic可能会给你一些解决这个问题的方法。

+1因为绑定是解决这类问题的“真实而专业”的答案。如果他确定$user_id是数字,他就不需要在SQL中插值周围加单引号。我认为这是使用单引号而不是双引号字符串,因此,您应该考虑使用绑定参数。你看起来很好,但是你不能确定下一个开发人员是否会在查询的前面添加另一个变量,因为它更容易受到攻击。数据库抽象层被高估了。在任何情况下,重要的是准备/执行范例,无论是由DAL完成的还是直接在数据库特定层中完成的。我可以反驳说,准备/执行被夸大了。:-)一个好的DAL就像其他任何抽象层一样:厚到可以使用,但不薄到只需要重命名函数。
$db_connection = new mysqli("localhost", "user", "pass", "db");
$statement = $db_connection->prepare("SELECT thing FROM stuff WHERE id = ?");
$statement->bind_param("i", $user_id); //$user_id is an integer which goes 
                                       //in place of ?
$statement->execute();