引言:SQL注入是一个老生常谈且又非常重要的漏洞,导致许多热点的数据泄露事件。尽管学习起来相对简单,但它可能用于某些高危漏洞的利用。这使得它成为初学者的兴趣点,甚至对于更有经验的用户来说,SQL注入也是基本知识。
SQL注入是一种利用应用程序对用户输入的处理不当,使恶意用户能够执行未经授权的SQL查询的行为。当应用程序从用户那里接收输入并将其直接用作SQL查询的一部分时,就可能发生SQL注入,使得攻击者能够干扰应用程序对数据库的正常查询,甚至可访问敏感数据,引起数据泄露。
SQL注入根源:
比如,通过输入"1 and version() > 0"
,若应用程序正常返回,说明version()
被数据库识别并执行。因version()
是Mysql特有的函数,所以可以推断出后台数据库为Mysql。
Note:不同数据库的注入点可以查阅https://portswigger.net/web-security/sql-injection/cheat-sheet
首先,你需要确定你想要攻击的目标。它可能是一个公开的网站,或者是一个内部网络应用。简而言之,你需要先找到一个有用户输入并且包含数据库连接信息的应用。
你需要寻找应用程序中可能存在SQL注入的点。注入点通常在用户输入字段(如用户名、密码、搜索查询等)中。当应用程序将这些输入直接插入到SQL查询中时,就可能存在注入风险。
常见注入点分类:
and 1=1
,and '1'='1
基于你找到的注入点,你需要构造一个恶意输入。这个输入可能包含一些特殊字符或字符串,这些字符或字符串会被应用程序误解为SQL代码。例如,如果你正在寻找用户名和密码字段,一个可能的恶意输入可能是“admin; SELECT * FROM users”
,这个输入会触发一个查询,返回所有用户的信息。
当你的恶意输入被提交到应用程序时,如果应用程序没有正确地验证和清理用户输入,那么它就会执行你构造的SQL代码。这可能导致数据库被篡改,或者敏感信息被泄露。
Note:通过构造特殊的SQL语句可猜测类似表名、字段名、用户名及密码信息。
一旦攻击成功,你需要分析数据库中的数据,以确认你的攻击是否成功。你可能需要查看特定的表或列,或者查看数据库的整体结构。
在不同的情况下会发生许多SQL注入漏洞、攻击和技术。一些常见的SQL注入示例包括:
xxx' and '1'='1
并不影响程序正常响应,但这可以确认此处存在注入点。主要有以下4种防御方法:参数化查询、存储过程、输入数据校验及最小化权限配置。
比如如下代码,直接通过拼接SQL方式执行查询,存储注入问题
String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
可修改为下面的预编译语句形式,利用预编译将SQL编译后放入缓存池,当服务器执行入参时并不会编译SQL,而是直接传参,所以可以避免SQL注入。
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();
使用存储过程也在可以缓解SQL注入,效果与预编译语句类似。区别在于存储过程需要先将SQL语句定义在数据库中,而非缓存池。
当然,在使用存储过程中也可能存在注入问题,需要尽量避免在存储过程内使用动态的SQL语句。如实在无法避免,可严格过滤输入或对输入编码后再处理。
对传入的数据类型做校验,比如只能是时间类型、整型,或满足指定格式(IP、邮箱格式)
避免对普通账号赋予过高的权限,数据库账户设计时需要遵循最小化权限原则。比如,只涉及查询类的应用,数据库账户只需要赋予只读权限即可,避免因注入问题导致下个数据库被删除;
[1] https://portswigger.net/web-security/sql-injection#what-is-sql-injection-sqli
前期回顾:
「 典型安全漏洞系列 」01.XSS攻击详解