Go--避免SQL注⼊
避免SQL注⼊
什么是SQL注⼊
SQL注⼊攻击(SQL Injection),简称注⼊攻击,是Web开发中最常见的⼀种安全漏洞。可以⽤它来从数据库获取敏感信息,或者利⽤数据库的特性执⾏添加⽤户,导出⽂件等⼀系列恶意操作,甚⾄有可能获取数据库乃⾄系统⽤户最⾼权限。正则匹配尖括号
⽽造成SQL注⼊的原因是因为程序没有有效过滤⽤户的输⼊,使攻击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输⼊作为查询语句的⼀部分执⾏,导致原始的查询逻辑被改变,额外的执⾏了攻击者精⼼构造的恶意代码。
SQL注⼊实例
很多Web开发者没有意识到SQL查询是可以被篡改的,从⽽把SQL查询当作可信任的命令。殊不知,SQL查询是可以绕开访问控制,从⽽绕过⾝份验证和权限检查的。更有甚者,有可能通过SQL查询去运⾏主机系统级的命令。
下⾯将通过⼀些真实的例⼦来详细讲解SQL注⼊的⽅式。
考虑以下简单的登录表单:
<form action="/login" method="POST">
<p>Username: <input type="text" name="username" /></p>
<p>Password: <input type="password" name="password" /></p>
<p><input type="submit" value="登陆" /></p>
</form>
我们的处理⾥⾯的SQL可能是这样的:
username:=r.Form.Get("username")
password:=r.Form.Get("password")
sql:="SELECT * FROM user WHERE username='"+username+"' AND password='"+password+"'"
如果⽤户的输⼊的⽤户名如下,密码任意
myuser' or 'foo' = 'foo' --
那么我们的SQL变成了如下所⽰:
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
下⾯是我测试的(可⽤), 上⾯我测试报错: = 附近有错误.
localhost:9900/CheckUser?name=admin' or USER_NAME ='admin' --&pwd=1
"SELECT USER_NAME, Pwd FROM [Sys_user] WHERE USER_NAME='admin' or USER_NAME ='admin' -- AND
Pwd='6UULGI0WaTiNLCsz9rkhCVIstiVtrX002Z4DBYzyizE="
在SQL⾥⾯--是注释标记,所以查询语句会在此中断。这就让攻击者在不知道任何合法⽤户名和密码的情况下成功登录了。
对于MSSQL还有更加危险的⼀种SQL注⼊,就是控制系统,下⾯这个可怕的例⼦将演⽰如何在某些版本的MSSQL数据库上执⾏系统命令。sql:="SELECT * FROM products WHERE name LIKE '%"+prod+"%'"
Db.Exec(sql)
如果攻击提交a%' p_cmdshell 'net user test testpass /ADD' --作为变量 prod的值,那么sql将会变成
sql:="SELECT * FROM products WHERE name LIKE '%a%' p_cmdshell 'net user test testpass /ADD'--%'"
MSSQL服务器会执⾏这条SQL语句,包括它后⾯那个⽤于向系统添加新⽤户的命令。如果这个程序是以sa运⾏⽽ MSSQLSERVER服务⼜有⾜够的权限的话,攻击者就可以获得⼀个系统帐号来访问主机了。
虽然以上的例⼦是针对某⼀特定的数据库系统的,但是这并不代表不能对其它数据库系统实施类似的攻击。针对这种安全漏洞,只要使⽤不同⽅法,各种数据库都有可能遭殃。
如何预防SQL注⼊
也许你会说攻击者要知道数据库结构的信息才能实施SQL注⼊攻击。确实如此,但没⼈能保证攻击者⼀定拿不到这些信息,⼀旦他们拿到了,数据库就存在泄露的危险。如果你在⽤开放源代码的软件包来访问数据库,⽐如论坛程序,攻击者就很容易得到相关的代码。如果这些
代码设计不良的话,风险就更⼤了。⽬前Discuz、phpwind、phpcms等这些流⾏的开源程序都有被SQL注⼊攻击的先例。
这些攻击总是发⽣在安全性不⾼的代码上。所以,永远不要信任外界输⼊的数据,特别是来⾃于⽤户的数据,包括选择框、表单隐藏域和cookie。就如上⾯的第⼀个例⼦那样,就算是正常的查询也有可能造成灾难。
SQL注⼊攻击的危害这么⼤,那么该如何来防治呢?下⾯这些建议或许对防治SQL注⼊有⼀定的帮助。
1. 严格限制Web应⽤的数据库的操作权限,给此⽤户提供仅仅能够满⾜其⼯作的最低权限,从⽽最⼤限度的减少注⼊攻击对数据库的危
害。
2. 检查输⼊的数据是否具有所期望的数据格式,严格限制变量的类型,例如使⽤regexp包进⾏⼀些匹配处理,或者使⽤strconv包对字符
串转化成其他基本类型的数据进⾏判断。
3. 对进⼊数据库的特殊字符('"\尖括号&*;等)进⾏转义处理,或编码转换。Go 的text/template包⾥⾯的HTMLEscapeString函数可以对字符串
进⾏转义处理。
4. 所有的查询语句建议使⽤数据库提供的参数化查询接⼝,参数化的语句使⽤参数⽽不是将⽤户输⼊变量嵌⼊到SQL语句中,即不要直
接拼接SQL语句。例如使⽤database/sql⾥⾯的查询函数Prepare和Query,或者Exec(query string, args ...interface{})。
5. 在应⽤发布之前建议使⽤专业的SQL注⼊检测⼯具进⾏检测,以及时修补被发现的SQL注⼊漏洞。⽹上有很多这⽅⾯的开源⼯具,例
如sqlmap、SQLninja等。
6. 避免⽹站打印出SQL错误信息,⽐如类型错误、字段不匹配等,把代码⾥的SQL语句暴露出来,以防⽌攻击者利⽤这些错误信息进⾏
SQL注⼊。
总结
通过上⾯的⽰例我们可以知道,SQL注⼊是危害相当⼤的安全漏洞。所以对于我们平常编写的Web应⽤,应该对于每⼀个⼩细节都要⾮常重视,细节决定命运,⽣活如此,编写Web应⽤也是这样。
package SQL_inject
import "regexp"
// 正则过滤sql注⼊的⽅法
/
/ 参数 : 要匹配的语句
func FilteredSQLInject(to_match_str string) bool {
//过滤 ‘
//ORACLE 注解 --  /**/
//关键字过滤 update ,delete
// 正则的字符串, 不能⽤ " " 因为" "⾥⾯的内容会转义
str := `(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|
(\b(select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|into|drop|execu te)\b)`
re, err := regexp.Compile(str)
if err != nil {
panic(err.Error())
return false
}
return re.MatchString(to_match_str)
这种⽅法是有缺陷的(⽤户名不能为update之类的), 可以⽤参数化查询来规避这种缺陷:
详见我的博客:
mysql参数化查询,防⽌Mysql注⼊

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。