SQL 注入连接与参数
SQL injection concatenation vs parameter
我一直在阅读一篇关于 sql 注入攻击的文章,在那里,他们一直在说这种说法容易受到注入攻击:
"SELECT * from tblBlah where userId" +userId
但是这个查询不是
"SELECT * from tblBlah where userId = @userId";
我正试图找到一个解释为什么会这样。他们都在期待一个参数。会不会是第一个查询可以接受来自 URL 的参数而第二个不能?
在第一个查询的情况下,有人可以为 userId
传递以下值:
= 3; DELETE FROM tblBlah;
这将是字符串连接并会导致以下 SQL 语句:
SELECT * from tblBlah where userId= 3; DELETE FROM tblBlah;
当然,这对您的数据库来说是灾难性的。
我认为在第二个查询的情况下,数据库会在内部将其编译为单个 SELECT
语句。参数的值将插入占位符所在的位置,但仅作为数据。即使我们尝试了以下分配:
@userId = '= 3; DELETE FROM tblBlah;';
我们最终会得到以下查询:
SELECT * from tblBlah where userId = '= 3; DELETE FROM tblBlah;';
换句话说,我们试图注入代码,但我们真正能做的只是注入一个字符串参数。这可能会导致错误的查询被触发,但它不会允许恶意用户调用 DELETE
。事实上,用户对执行哪个语句的控制是零。
这是一个简单的示例,展示了准备语句的强大功能。对于准备好的语句,查询的一般模板或结构在查询实际运行之前就已经编译好了。语句的某些部分具有参数占位符,但不会通过串联更改查询,而只会通过分配定位值来更改查询。
对于您的第一个查询,数据库不知道它是否有更多条件或查询的确切目的是什么,然后数据库将以盲目方式信任该查询。
在第二个数据库中,启动时的数据库将获取查询并确切知道你想要做什么以及查询应该有多少参数,如果来自参数的某些东西改变了初始行为,或者根本不存在,查询将不受信任并会抛出错误。
我现在举例说明。
如果你这样做:
SELECT * FROM table WHERE User=' + User + ' AND Pwd=' + Pass
有人可以很容易地在那里注入 SQL,只需用 '' AND 1=1--
填充用户,因为 --
会注释掉查询的第二部分并且条件为真,那么它将打印 table 数据。
查询如下所示:
SELECT * FROM table WHERE User='' AND 1=1-- AND Pwd=' + Pass
现在让我们用参数来做:
SELECT * FROM custTable WHERE User= @user AND Pass=@password
//Someone filled the userfield with SQL injection:
@user = "'' AND 1=1--"
@password = ""
那么查询将如下所示:
SELECT * FROM custTable WHERE User= '' AND 1=1-- AND Pass=@password
查询看起来相同但工作方式不同,数据库将处理查询,获取@username 参数和空白密码,然后它应该为 false。
我要补充的是,这取决于您如何使用 SQL 参数以及您使用哪种语言编程,它或多或少会安全,但最安全的方法之一是使用存储过程参数化查询。
我一直在阅读一篇关于 sql 注入攻击的文章,在那里,他们一直在说这种说法容易受到注入攻击:
"SELECT * from tblBlah where userId" +userId
但是这个查询不是
"SELECT * from tblBlah where userId = @userId";
我正试图找到一个解释为什么会这样。他们都在期待一个参数。会不会是第一个查询可以接受来自 URL 的参数而第二个不能?
在第一个查询的情况下,有人可以为 userId
传递以下值:
= 3; DELETE FROM tblBlah;
这将是字符串连接并会导致以下 SQL 语句:
SELECT * from tblBlah where userId= 3; DELETE FROM tblBlah;
当然,这对您的数据库来说是灾难性的。
我认为在第二个查询的情况下,数据库会在内部将其编译为单个 SELECT
语句。参数的值将插入占位符所在的位置,但仅作为数据。即使我们尝试了以下分配:
@userId = '= 3; DELETE FROM tblBlah;';
我们最终会得到以下查询:
SELECT * from tblBlah where userId = '= 3; DELETE FROM tblBlah;';
换句话说,我们试图注入代码,但我们真正能做的只是注入一个字符串参数。这可能会导致错误的查询被触发,但它不会允许恶意用户调用 DELETE
。事实上,用户对执行哪个语句的控制是零。
这是一个简单的示例,展示了准备语句的强大功能。对于准备好的语句,查询的一般模板或结构在查询实际运行之前就已经编译好了。语句的某些部分具有参数占位符,但不会通过串联更改查询,而只会通过分配定位值来更改查询。
对于您的第一个查询,数据库不知道它是否有更多条件或查询的确切目的是什么,然后数据库将以盲目方式信任该查询。
在第二个数据库中,启动时的数据库将获取查询并确切知道你想要做什么以及查询应该有多少参数,如果来自参数的某些东西改变了初始行为,或者根本不存在,查询将不受信任并会抛出错误。
我现在举例说明。
如果你这样做:
SELECT * FROM table WHERE User=' + User + ' AND Pwd=' + Pass
有人可以很容易地在那里注入 SQL,只需用 '' AND 1=1--
填充用户,因为 --
会注释掉查询的第二部分并且条件为真,那么它将打印 table 数据。
查询如下所示:
SELECT * FROM table WHERE User='' AND 1=1-- AND Pwd=' + Pass
现在让我们用参数来做:
SELECT * FROM custTable WHERE User= @user AND Pass=@password
//Someone filled the userfield with SQL injection:
@user = "'' AND 1=1--"
@password = ""
那么查询将如下所示:
SELECT * FROM custTable WHERE User= '' AND 1=1-- AND Pass=@password
查询看起来相同但工作方式不同,数据库将处理查询,获取@username 参数和空白密码,然后它应该为 false。
我要补充的是,这取决于您如何使用 SQL 参数以及您使用哪种语言编程,它或多或少会安全,但最安全的方法之一是使用存储过程参数化查询。