Files
build-web-application-with-…/zh-tw/09.4.md
2019-02-26 01:40:54 +08:00

79 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 9.4 避免SQL注入
## 什麼是SQL注入
SQL注入攻擊SQL Injection簡稱注入攻擊是Web開發中最常見的一種安全漏洞。可以用它來從資料庫取得敏感資訊或者利用資料庫的特性執行新增使用者匯出檔案等一系列惡意操作甚至有可能取得資料庫乃至系統使用者最高許可權。
而造成SQL注入的原因是因為程式沒有有效過濾使用者的輸入使攻擊者成功的向伺服器提交惡意的SQL查詢程式碼程式在接收後錯誤的將攻擊者的輸入作為查詢語句的一部分執行導致原始的查詢邏輯被改變額外的執行了攻擊者精心構造的惡意程式碼。
## SQL注入例項
很多Web開發者沒有意識到SQL查詢是可以被篡改的從而把SQL查詢當作可信任的命令。殊不知SQL查詢是可以繞開訪問控制從而繞過身份驗證和許可權檢查的。更有甚者有可能透過SQL查詢去執行主機系統級的命令。
下面將透過一些真實的例子來詳細講解SQL注入的方式。
考慮以下簡單的登入表單:
```html
<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可能是這樣的
```Go
username:=r.Form.Get("username")
password:=r.Form.Get("password")
sql:="SELECT * FROM user WHERE username='"+username+"' AND password='"+password+"'"
```
如果使用者的輸入的使用者名稱如下,密碼任意
```Go
myuser' or 'foo' = 'foo' --
```
那麼我們的SQL變成了如下所示
```Go
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
```
在SQL裡面`--`是註釋標記,所以查詢語句會在此中斷。這就讓攻擊者在不知道任何合法使用者名稱和密碼的情況下成功登入了。
對於MSSQL還有更加危險的一種SQL注入就是控制系統下面這個可怕的例子將示範如何在某些版本的MSSQL資料庫上執行系統命令。
```Go
sql:="SELECT * FROM products WHERE name LIKE '%"+prod+"%'"
Db.Exec(sql)
```
如果攻擊提交`a%' exec master..xp_cmdshell 'net user test testpass /ADD' --`作為變數 prod的值那麼sql將會變成
```Go
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>)