简介
SQL注入作为一种攻击方式最早可以追溯到20世纪90年代中期,当时Web应用程序开始流行并广泛使用数据库作为其后端数据存储。最早的SQL注入攻击是通过简单地在Web表单输入框中输入SQL代码来实现的,攻击者可以通过修改输入参数来篡改数据库查询的行为,从而窃取数据或者破坏数据库的完整性。
自那时以来,SQL注入已经成为一种常见的网络攻击方式,尤其是对于那些没有充分考虑安全性的Web应用程序而言。许多著名的数据泄露事件和网络攻击都与SQL注入有关。因此,保护Web应用程序免受SQL注入攻击已经成为网络安全的一个重要领域。随着安全意识的不断提高,开发人员和安全专家已经采取了许多措施来预防和检测SQL注入攻击,如输入验证、参数化查询、安全编码实践等。
简单来说,sql注入就是将用户的参数带入到了数据库查询中
漏洞代码:
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
这串代码直接将用户输入的参数赋予到id变量里,然后带入数据库里查询
sql注入的攻击方法:
union联合查询注入 ,报错注入 ,时间盲注,布尔盲注 ,堆叠查询注入 ,宽字节注入
union联合查询注入
SQL注入中的联合查询注入(Union-Based Injection)是一种常见的攻击方式,利用SQL语句中的UNION操作符来实现。联合查询通常用于将两个或多个查询结果合并为单个结果集。攻击者可以通过在一个SQL语句中插入恶意代码,从而将另一个查询结果集合并到原始结果集中,从而获得未经授权的访问和操作权限。
在联合查询注入中,攻击者会利用UNION操作符来合并两个查询结果,通常会插入一些恶意代码,例如’OR 1=1’或者’–',这些代码会干扰原始查询的逻辑,并将攻击者的查询结果集合并到原始结果集中。攻击者可以通过这种方式窃取数据、执行未经授权的操作、绕过身份验证等
假设有一个简单的用户登录页面,其中用户名和密码通过POST请求发送到服务器,服务器接收到请求后将其拼接成SQL查询语句,查询语句如下:
SELECT * FROM users WHERE username='[用户名]' AND password='[密码]'
攻击者可以利用联合查询注入来绕过身份验证,以下是一个可能的攻击示例:
假设攻击者输入的用户名是 ’ or 1=1 union select 1,2,3–,这个输入会将原始查询语句修改为:
SELECT * FROM users WHERE username='' or 1=1 union select 1,2,3--' AND password='[密码]'
这个修改后的查询语句会执行两个查询,第一个查询会返回所有用户,因为 1=1 是恒成立的条件。第二个查询是一个带有三个列的伪查询,其中每个列都是常量 1、2、3,攻击者可以通过这个查询来获取有关数据表结构和内容的信息。因此,攻击者可以通过这种方式获得未经授权的访问和操作权限。
报错注入
报错注入(Error-Based Injection)是SQL注入攻击中的一种常见方式。攻击者利用错误消息来了解SQL查询中的错误,从而推断出数据表的结构和内容,进而获取敏感信息。
报错注入攻击通常通过向SQL查询中注入恶意代码来实现,例如,在查询语句的末尾添加 AND 1=2 UNION SELECT 1/0,这将导致查询语句执行错误并返回一个错误消息。攻击者可以从错误消息中了解SQL查询中发生了什么,并利用这些信息来推断数据表的结构和内容。
例如,如果错误消息显示列 user_password 不存在,那么攻击者可以推断出该数据表包含列 user_password,并利用这个信息来发起其他SQL注入攻击,从而获取敏感数据
假设有一个包含用户数据的数据表,包括用户名、电子邮件和密码,其中密码是经过哈希处理的。现在,我们要实现一个简单的用户登录功能,用户可以通过输入用户名和密码来登录系统。查询语句如下:
SELECT * FROM users WHERE username = '[用户名]' AND password = '[密码]'
攻击者可以通过报错注入攻击来绕过密码验证,以下是一个可能的攻击示例:
假设攻击者输入的用户名是 ’ or 1=1 union select 1,2,3 from users–,这个输入会将原始查询语句修改为:
SELECT * FROM users WHERE username = '' or 1=1 union select 1,2,3 from users--' AND password = '[密码]'
这个修改后的查询语句将执行两个查询。第一个查询是原始查询,它将返回所有用户。第二个查询是一个带有三个列的伪查询,其中每个列都是常量 1、2、3,并且从原始数据表中查询数据。但是,由于第二个查询中的列与数据表的实际列不匹配,所以将会返回一个错误消息,例如:
Unknown column 'password' in 'where clause'
攻击者可以从这个错误消息中了解到数据表中不包含 password 列,从而推断出该数据表包含三列,分别是 username、email 和 password。攻击者可以继续利用这些信息来发起其他SQL注入攻击,例如:
假设攻击者想要获取所有用户的电子邮件地址,攻击者可以使用以下查询语句:
' or 1=1 union select null,email,null from users--
这个查询语句将返回一个伪查询,其中只有电子邮件列是真实的,而其他两列都是空值。
时间盲注
时间盲注(Time-Based Blind Injection)是一种SQL注入攻击方法,攻击者通过发送恶意的SQL查询语句来检测数据表中的信息,而不需要从返回的结果中获取明确的信息。
攻击者利用时间函数来检查查询的结果是否满足某个条件,如果满足,就会延长查询时间或者在响应中增加一个时间延迟。例如,攻击者可以发送以下查询:
SELECT * FROM users WHERE id = 1 AND (SELECT 1 FROM users WHERE username = 'admin' AND ASCII(SUBSTRING(password,1,1)) = 97)
该查询语句中的 ASCII() 函数会将密码中第一个字符转换为其ASCII码,并将其与字符"a"的ASCII码进行比较。如果密码的第一个字符是"a",那么查询将返回TRUE,否则返回FALSE。
攻击者可以根据查询返回的响应时间来推断查询结果是否为TRUE。如果查询结果为TRUE,则响应时间通常会更长,因为查询需要执行更多的操作。通过不断地调整查询条件,攻击者可以逐步推断出密码中的每个字符,最终获得完整的密码
假设我们有一个简单的用户登录系统,其登录页面包含两个输入框:用户名和密码。当用户提交登录请求时,应用程序将执行以下SQL查询语句:
SELECT * FROM users WHERE username = 'input_username' AND password = 'input_password';
攻击者可以利用时间盲注来试图猜测正确的用户名和密码,从而绕过身份验证并获得对应用程序的访问权限。
攻击者可以向用户名输入框中输入一个有效的用户名(如 “admin”),然后在密码输入框中输入以下内容:
' AND IF(SUBSTR((SELECT password FROM users WHERE username='admin'),1,1)='a',SLEEP(5),0) AND '
该SQL查询语句中的 IF() 函数将检查密码中的第一个字符是否等于字符"a"。如果是,查询将会执行一个5秒钟的时间延迟。如果不是,则查询不会执行延迟。
如果应用程序容易受到时间盲注攻击,那么攻击者可以通过观察登录请求的响应时间来确定密码中的第一个字符是否等于字符"a"。如果响应时间超过5秒钟,则说明第一个字符是"a",否则就不是。
接下来,攻击者可以逐一检查密码中的每个字符,将上述语句中的“1”更改为“2”,并将“SUBSTR()”函数的第二个参数增加1。如果查询的响应时间大于5秒,则说明密码中的第二个字符是正确的,否则就不是。
通过这种方式,攻击者可以不断地迭代查询条件,直到成功地猜测出正确的用户名和密码,并获得对应用程序的访问权限
布尔盲注
布尔盲注是一种 SQL 注入攻击技术,它利用了应用程序在响应中不提供明确错误消息的情况下执行 SQL 查询的行为。攻击者可以使用布尔盲注来推断关于数据库中数据的信息,包括表、列、行和值。
布尔盲注的攻击思路是利用布尔逻辑表达式,通过不断构造逻辑表达式,来逐步推断出所需要的信息。比如,我们可以使用以下 SQL 语句来判断某个条件是否为真:
SELECT * FROM users WHERE username = 'admin' AND password LIKE '%a%';
如果该语句返回结果,则说明密码中包含字符 “a”,否则就不包含。
使用这种方法,攻击者可以通过构造一系列逻辑表达式来推断关于数据库的信息,例如:
SELECT * FROM users WHERE username = 'admin' AND password LIKE 'a%';
SELECT * FROM users WHERE username = 'admin' AND password LIKE 'aa%';
SELECT * FROM users WHERE username = 'admin' AND password LIKE 'ab%';
如果第一个语句返回结果,而第二个语句没有返回结果,则可以推断出密码的第二个字符是 “a”,否则就是 “b”。
通过这种方式,攻击者可以使用布尔盲注攻击来推断出数据库中的敏感信息,如用户名和密码。
假设一个网站有一个搜索功能,可以根据输入的关键词在数据库中搜索匹配的文章。搜索功能的代码如下:
<?php
$keyword = $_GET['keyword'];
$sql = "SELECT * FROM articles WHERE title LIKE '%$keyword%'";
$result = mysql_query($sql);
?>
上面的代码有一个明显的 SQL 注入漏洞,攻击者可以在 keyword 参数中注入恶意的 SQL 代码。使用布尔盲注攻击可以让攻击者逐步推断出数据库中的信息,如下所示:
首先,我们可以构造以下请求:
http://example.com/search.php?keyword=a' AND 1=1--
这将导致 SQL 语句变为以下形式:
SELECT * FROM articles WHERE title LIKE '%a' AND 1=1--%'
这个语句将返回所有标题中包含字符 “a” 的文章,同时忽略后面的注释。
接下来,我们可以构造以下请求:
http://example.com/search.php?keyword=a' AND substring((SELECT password FROM users WHERE username='admin'),1,1)='a'--
这将导致 SQL 语句变为以下形式:
SELECT * FROM articles WHERE title LIKE '%a' AND substring((SELECT password FROM users WHERE username='admin'),1,1)='a'--%'
如果这个语句返回结果,则说明管理员的密码以 “a” 开头,否则就不是。
使用类似的方式,攻击者可以逐步推断出管理员的密码。例如,使用以下请求可以检查密码的第二个字符:
http://example.com/search.php?keyword=a' AND substring((SELECT password FROM users WHERE username='admin'),2,1)='b'--
如果这个语句返回结果,则说明管理员的密码的第二个字符是 “b”,否则就不是。
通过这种方式,攻击者可以逐步推断出管理员的密码,并最终登录到网站上执行恶意操作。
堆叠查询注入
SQL注入的堆叠查询注入(Stacked Query Injection)是一种SQL注入技术,攻击者可以在一次数据库查询中执行多个查询语句,以达到执行任意SQL语句的目的。
堆叠查询注入通常是在执行多条SQL语句的Web应用程序中发现的,例如使用多个SQL查询更新或插入多个值的程序,或使用存储过程或触发器的程序。
攻击者通过在Web应用程序的输入字段中插入特殊字符和SQL代码来实现堆叠查询注入攻击。攻击者通常使用分号“;”或双破折号“–”来分隔多个查询语句
假设有一个网站提供了一个搜索功能,用户可以输入一个关键词来搜索相关内容。该网站使用了如下的 SQL 查询来实现搜索:
SELECT * FROM products WHERE name LIKE '%keyword%';
其中 keyword 是用户输入的搜索关键词。
攻击者可以通过在关键词中注入恶意的 SQL 代码来实现注入攻击。例如,攻击者可以将关键词输入改为:
'; SELECT * FROM users;--
这将导致 SQL 语句变为以下形式:
SELECT * FROM products WHERE name LIKE ''; SELECT * FROM users;-- %';
注意到这个查询语句包含两个独立的 SQL 查询,以分号 ; 分隔。由于在这种情况下,查询中包含两个分号,因此查询将无法正常执行,会抛出一个 SQL 错误。攻击者可以通过使用堆叠查询技术来绕过这个限制。
例如,攻击者可以将关键词输入改为:
'; SELECT * FROM users WHERE id=1; INSERT INTO products(name) VALUES ('hacked');--
这将导致 SQL 语句变为以下形式:
SELECT * FROM products WHERE name LIKE ''; SELECT * FROM users WHERE id=1; INSERT INTO products(name) VALUES ('hacked');-- %';
在这个查询语句中,攻击者在第一个查询中插入了一个空字符串 ‘’,然后在第二个查询中获取 users 表中 id=1 的记录,并在第三个查询中插入一条新的产品记录。这些查询会被顺序执行,而且它们都是有效的 SQL 查询,因此可以成功执行。
通过这种方式,攻击者可以在不知道任何表结构的情况下执行任意的 SQL 代码,包括获取、修改、删除敏感数据等操作
宽字节注入
SQL注入的宽字节注入(Wide-Character Encoding)是一种利用Web应用程序中使用不安全字符编码方式的SQL注入技术。它是一种比较常见的SQL注入方式,也是一种相对难以检测和防御的攻击。
宽字节注入利用了一些Web应用程序在处理输入时所使用的编码方式,通常是将输入转换为Unicode编码或其他字符编码方式。攻击者可以在输入中插入特殊字符和SQL代码,以达到执行任意SQL语句的目的。
在宽字节注入中,攻击者使用一些特殊字符(如%df%27)替换原始输入中的某些字符,从而使SQL语句变得不规则或不完整。这样可以绕过应用程序中的一些安全检测机制,使应用程序执行攻击者构造的恶意SQL语句
假设一个使用 MySQL 数据库的网站,其中有一个搜索页面,允许用户搜索特定的产品。网站的 URL 可能看起来像这样:
https://example.com/search.php?keyword=product_name
在这里,product_name 是用户输入的产品名称。搜索页面将用户输入的 product_name 值传递给后端的 MySQL 查询。查询可能类似于以下内容:
SELECT * FROM products WHERE name = 'product_name'
在这里,product_name 是用户输入的值,该值将用于 SQL 查询中的 name 列。
攻击者可能会利用 MySQL 的宽字符编码,将 product_name 中的 ’ 转换为 %df%27。如果网站没有正确地处理这种编码,攻击者就可以利用宽字节注入进行 SQL 注入攻击。例如,攻击者可能会输入以下内容:在这里,product_name 是用户输入的值,该值将用于 SQL 查询中的 name 列。
攻击者可能会利用 MySQL 的宽字符编码,将 product_name 中的 ’ 转换为 %df%27。如果网站没有正确地处理这种编码,攻击者就可以利用宽字节注入进行 SQL 注入攻击。例如,攻击者可能会输入以下内容:
product_name=%df%27%20OR%20%271%27%3D%271
在这里,攻击者使用 %df%27 编码的单引号 ’ 和 %20 编码的空格字符 。攻击者还使用 OR 运算符和恒等式 1=1 来注入一个永远为真的条件。如果网站没有正确地处理宽字符编码,那么 product_name 的值将被解释为以下内容:
SELECT * FROM products WHERE name = '%df%27 OR '1'='1'
在这里,第二个查询将始终返回所有产品行,因为 1=1 恒为真。攻击者成功地执行了 SQL 注入攻击,从而可以访问敏感信息或控制整个数据库
绕过WAF的一些手段
WAF(Web Application Firewall)是一种用于保护 Web 应用程序免受恶意攻击的安全设备。当 WAF 配置正确并正确地执行时,它可以有效地防止许多类型的攻击,包括 SQL 注入。但是,攻击者可能会使用一些技术来绕过 WAF 的保护。以下是一些可能用于绕过 WAF 的 SQL 注入技术:
1.通过混淆和编码来绕过 WAF 检测
攻击者可以对 SQL 查询中的关键词和语法进行混淆和编码,以避免被 WAF 检测到。例如,攻击者可能会使用 URL 编码、十六进制编码、Unicode 编码、Base64 编码等技术对 SQL 查询进行编码,使 WAF 无法识别其中的恶意内容。
2.使用换行符绕过 WAF 检测
攻击者可能会使用换行符来绕过 WAF 的检测。这是因为 WAF 通常只检查单个 HTTP 请求,而 SQL 查询通常跨越多个行。因此,攻击者可以使用换行符来将 SQL 查询拆分成多个行,以避免被 WAF 检测到。
3.使用 HTTP 动词绕过 WAF 检测
WAF 通常只检查 HTTP GET 和 POST 请求中的参数,而不会检查其他 HTTP 动词,例如 PUT、DELETE、OPTIONS 等。攻击者可能会使用这些未被检查的 HTTP 动词来提交恶意 SQL 查询,以避免被 WAF 检测到。
4.使用双重编码绕过 WAF 检测
攻击者可能会使用双重编码来绕过 WAF 的检测。例如,攻击者可能会将 SQL 查询使用 URL 编码进行编码,然后再对结果再进行一次 Base64 编码,以使 WAF 无法识别其中的恶意内容。
5.拆分字符串
将注入语句拆分为多个小的字符串,逐一传递给服务器执行,以此规避 WAF 的检测