Merging other languages
This commit is contained in:
144
en/09.4.md
144
en/09.4.md
@@ -1,69 +1,75 @@
|
||||
# 9.4 避免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'
|
||||
|
||||
在SQL里面`--`是注释标记,所以查询语句会在此中断。这就让攻击者在不知道任何合法用户名和密码的情况下成功登录了。
|
||||
|
||||
对于MSSQL还有更加危险的一种SQL注入,就是控制系统,下面这个可怕的例子将演示如何在某些版本的MSSQL数据库上执行系统命令。
|
||||
|
||||
sql:="SELECT * FROM products WHERE name LIKE '%"+prod+"%'"
|
||||
Db.Exec(sql)
|
||||
|
||||
如果攻击提交`a%' exec master..xp_cmdshell 'net user test testpass /ADD' --`作为变量 prod的值,那么sql将会变成
|
||||
|
||||
sql:="SELECT * FROM products WHERE name LIKE '%a%' exec master..xp_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应用也是这样。
|
||||
|
||||
## links
|
||||
* [目录](<preface.md>)
|
||||
* 上一节: [避免XSS攻击](<09.3.md>)
|
||||
* 下一节: [存储密码](<09.5.md>)
|
||||
# 9.4 SQL injection
|
||||
|
||||
## What is SQL injection
|
||||
|
||||
SQL injection attacks are (as the name would suggest) one of the many types of script injection attacks. In web development, these are the most common form of security vulnerabilities. Attackers can use it to obtain sensitive information from databases, and aspects of an attack can involve adding users to the database, exporting private files, and even obtaining the highest system privileges for their own nefarious purposes.
|
||||
|
||||
SQL injection occurs when web applications do not effectively filter out user input, leaving the door wide open for attackers to submit malicious SQL query code to the server. Applications often receive injected code as part of an attacker's input, which alters the logic of the original query in some way. When the application attempts to execute the query, the attacker's malicious code is executed instead.
|
||||
|
||||
## SQL injection examples
|
||||
|
||||
Many web developers do not realize how SQL queries can be tampered with, and may hold the misconception that they are trusted commands. As everyone knows, SQL queries are able to circumvent access controls, thereby bypassing the standard authentication and authorization checks. What's more, it's possible to run SQL queries through commands at the level of the host system.
|
||||
|
||||
Let's have a look at some real examples to explain the process of SQL injection in detail.
|
||||
|
||||
Consider the following simple login form :
|
||||
|
||||
<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="Login" /></p>
|
||||
</form>
|
||||
|
||||
Our form processing might look like this:
|
||||
|
||||
username := r.Form.Get("username")
|
||||
password := r.Form.Get("password")
|
||||
sql := "SELECT * FROM user WHERE username='" + username + "' AND password='" + password + "'"
|
||||
|
||||
If the user inputs a user name or password as:
|
||||
|
||||
myuser' or 'foo' = 'foo' --
|
||||
|
||||
Then our SQL becomes the following:
|
||||
|
||||
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
|
||||
|
||||
In SQL, anything after `--` is a comment. Thus, inserting the `--` as the attacker did above alters the query in a fatal way, allowing an attacker to successfully login as a user without a valid password.
|
||||
|
||||
Far more dangerous exploits exist for MSSQL SQL injections, and some can even perform system commands. The following examples will demonstrate how terrible SQL injections can be in some versions of MSSQL databases.
|
||||
|
||||
sql := "SELECT * FROM products WHERE name LIKE '%" + prod + "%'"
|
||||
Db.Exec(sql)
|
||||
|
||||
If an attacker submits `a%' exec master..xp_cmdshell 'net user test testpass /ADD' --` as the "prod" variable, then the sql will become
|
||||
|
||||
sql := "SELECT * FROM products WHERE name LIKE '%a%' exec master..xp_cmdshell 'net user test testpass /ADD'--%'"
|
||||
|
||||
The MSSQL Server executes the SQL statement including the commands in the user supplied "prod" variable, which adds new users to the system. If this program is run as is, and the MSSQLSERVER service has sufficient privileges, an attacker can register a system account to access this machine.
|
||||
|
||||
> Although the examples above are tied to a specific database system, this does not mean that other database systems cannot be subjected to similar types of attacks. The principles behind SQL injection attacks remain the same, though the method with which they are perpetrated may vary.
|
||||
|
||||
## How to prevent SQL injection
|
||||
|
||||
You might be thinking that an attacker would have to know information about the target database's structure in order to carry out an SQL injection attack. While this is true, it's difficult to guarantee that an attacker won't be able to find this information and once they get it, the database can be compromised. If you are using open source software to access the database, such as a forum application, intruders can easily get the related code. Obviously with poorly designed code, the security risks are even greater. Discuz, phpwind and phpcms are some examples of popular open source programs that have been vulnerable to SQL injection attacks.
|
||||
|
||||
These attacks happen to systems where safety precautions are not prioritized. We've said it before, we'll say it again: never trust any kind of input, especially user data. This includes data coming from selection boxes, hidden input fields or cookies. As our first example above has shown, even supposedly normal queries can cause disasters.
|
||||
|
||||
SQL injection attacks can be devastating -how can do we even begin to defend against them? The following suggestions are a good starting point for preventing SQL injection:
|
||||
|
||||
1. Strictly limit permissions for database operations so that users only have the minimum set of permissions required to accomplish their work, thus minimizing the risk of database injection attacks.
|
||||
2. Check that input data has the expected data format, and strictly limit the types of variables that can be submitted. This can involve regexp matching, or using the strconv package to convert strings into other basic types for sanitization and evaluation.
|
||||
3. Transcode or escape from pairs of special characters ( '"\&*; etc. ) before persisting them into the database. Go's `text/template` package has a `HTMLEscapeString` function that can be used to return escaped HTML.
|
||||
4. Use your database's parameterized query interface. Parameterized statements use parameters instead of concatenating user input variables in embedded SQL statements; in other words, they do not directly splice SQL statements. For example, using the the `Prepare` function in Go's `database/sql` package, we can create prepared statements for later execution with `Query` or `Exec(query string, args... interface {})`.
|
||||
5. Before releasing your application, thoroughly test it using professional tools for detecting SQL injection vulnerabilities and to repair them, if they exist. There are many online open source tools that do just this, such as sqlmap, SQLninja, to name a few.
|
||||
6. Avoid printing out SQL error information on public webpages. Attackers can use these error messages to carry out SQL injection attacks. Examples of such errors are type errors, fields not matching errors, or any errors containing SQL statements.
|
||||
|
||||
## Summary
|
||||
|
||||
Through the above examples, we've learned that SQL injection is a very real and very dangerous web security vulnerability. When we write web application, we should pay attention to every little detail and treat security issues with the utmost care. Doing so will lead to better and more secure web applications, and can ultimately be the determing factor in whether or not your application succeeds.
|
||||
|
||||
## Links
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [XSS attacks](09.3.md)
|
||||
- Next section: [Password storage](09.5.md)
|
||||
|
||||
Reference in New Issue
Block a user