SQL 注入
什麼是 SQL 注入
SQL 注入,顧名思義就是通過注入 SQL 命令來進行攻擊,更確切地說攻擊者把 SQL 命令插入到 web 表單或請求參數的查詢字符串裏面提交給服務器,從而讓服務器執行編寫的惡意的 SQL 命令。
對於 web 開發者來說,SQL 注入已然是非常熟悉的,而且 SQL 注入已經生存了 10 多年,目前已經有很成熟的防範方法,所以目前的 web 應用都很少會存在漏洞允許進行 SQL 注入攻擊。 除非是入門開發人員,在開發的時候仍使用舊的技術去實現(比如 Java 的 Statement 和 PreparedStatement)
SQL 注入漏洞產生的原因
從上面可知,SQL 注入是通過讓服務器執行了惡意的 SQL 命令從而進行攻擊的,那麼主要問題就出在於服務器是如何生成 SQL 語句的。其實絕大多數擁有 SQL 注入漏洞的 Web 系統,在生成 SQL 語句的時候,採用的是拼接字符串的方式,並且沒有對要組裝成 SQL 語句的參數進行檢驗和過濾。
常見場景
下面就以一個用戶登陸的場景來講解
現在我們的數據庫中有一個用戶表(t_user),假設表裏面只有兩個元素,分別是用戶名和密碼
然後在 web 應用中,一般在用戶登錄時,驗證的方法一般都是通過賬號和密碼去獲取數據表中是否存在這樣的記錄,存在則返回用戶,不存在則返回 null;
那麼我們的 SQL 語句大概就會像這樣
SELECT username FROM t_user WHERE username = ‘xxx’ AND password = ‘xxx’
以 Java 爲例(使用拼接字符串的形式)
那麼此時我在登陸頁面輸入以下信息
賬號: 1’ or 1
密碼: xxx(隨意)
那麼服務器會生成這樣的 SQL 語句
SELECT username from t_user where username = ‘1’ or 1 and password = ‘xxx’
知道一點關係邏輯的人都知道這樣的條件查詢總會返回記錄,有記錄則代表登陸成功,則用戶不需要知道正確的賬號密碼就能登陸系統,如果是登陸前臺,那可能還好;可如果他拿到了後臺管理的鏈接,登陸進去了後臺,那麼你的系統可能就會被惡意破壞了。
從代碼中可以看到若是採用這種拼接字符串的形式來生成 SQL 語句,那麼這就會給 SQL 注入提供了機會。
那麼此時我在登陸頁面輸入以下信息
賬號: 1’ or 1
密碼: xxx(隨意)
那麼服務器會生成這樣的 SQL 語句
SELECT username from t_user where username = ‘1’ or 1 and password = ‘xxx’
知道一點關係邏輯的人都知道這樣的條件查詢總會返回記錄,有記錄則代表登陸成功,則用戶不需要知道正確的賬號密碼就能登陸系統,如果是登陸前臺,那可能還好;可如果他拿到了後臺管理的鏈接,登陸進去了後臺,那麼你的系統可能就會被惡意破壞了。
從代碼中可以看到若是採用這種拼接字符串的形式來生成 SQL 語句,那麼這就會給 SQL 注入提供了機會。
總結
在開發 web 應用時,應當儘量避免使用拼接字符串的方式來生成 SQL 語句,而且要特別注意檢查含有拼接字符串類型的參數的 SQL 語句,儘可能地去測試是否會有 SQL 注入漏洞。
XSS 攻擊
什麼是 XSS
XSS ,全名:cross-site scripting(跨站點腳本),是當前 web 應用中最危險和最普遍的漏洞之一。攻擊者嘗試注入惡意腳本代碼到受信任的網站上執行惡意操作,用戶使用瀏覽器瀏覽含有惡意腳本頁面時,會執行該段惡意腳本,進而影響用戶(比如關不完的網站、盜取用戶的 cookie 信息從而僞裝成用戶去操作)等等。
他與 SQL 注入很類似,同樣是通過注入惡意指令來進行攻擊。但 SQL 注入是在服務器端上執行的,而 XSS 攻擊是在客戶端上執行的,這點是他們本質區別。
XSS 的種類
XSS 攻擊的分類沒有標準,但普遍分爲三類:
- 反射型XSS(非持久性跨站攻擊)
- 存儲型XSS(持久性跨站攻擊
- DOM Based XSS(基於 dom 的跨站點腳本攻擊)
下面將直接以一些小例子來說明以上三種類別的 XSS 攻擊分別是怎樣的
反射型 XSS(非持久性跨站攻擊)
一般是利用網站某些頁面會直接輸出請求參數的特性,通過在 url 的請求參數包含惡意腳本,導致用戶打開該 url 的時候,執行惡意腳本。
例:http://localhost:8080/test.jsp?abc= <script>alert(“123”) </script>
用戶在訪問這個頁面的時候,就會觸發彈窗
當然,一般的 XSS 攻擊不會這麼簡單的就讓你彈個窗,可能他會讓你不斷彈窗(對你惡作劇),也可能會盜取你的信息等;而且一般這種形式的 url 會感覺很奇怪,哪有用戶會去打開這種奇怪的 url,所以一般會經過一定的包裝來欺騙用戶。
存儲型 XSS(持久性跨站攻擊)
該種類型的攻擊一般是通過表單輸入(比如發佈文章、回覆評論等功能中)插入一些惡意腳本,並且保存到數據庫,待其他用戶加載對應的頁面的時候,該段腳本就會被加載並執行。
與反射型 XSS 相比,該類的攻擊更具有危害性,因爲它影響的不只是一個用戶,而是大量用戶,而且該種類型還可進行蠕蟲傳播;就如之前的貼吧和微博事件,用戶訪問了含有惡意腳本的頁面,用戶的 cookie 信息被盜取了,並且立刻使用用戶的賬戶去發表新的帖子或微博同時注入惡意腳本,使得該惡意腳本不斷被傳播下去。
DOM Based XSS(基於 Dom 的跨站點腳本)
基於 DOM 的跨站點腳本與前面兩種類型有什麼區別呢?其實它注入的方式是基於前面兩種類型的方式的,只不過是注入的腳本是通過改變 DOM 來實施的。採用該種方式有一個好處就是從源代碼中不易被發現而已。
XSS 攻擊漏洞產生的原因
主要原因與 SQL 注入很類似,都是由於開發人員沒有對用戶輸入進行編碼和過濾。另一個原因是,這種攻擊方法有很多變體,要設計出一個能完全防禦的 XSS 過濾器是非常困難的。
如何去防護 XSS
基於上面漏洞產生的原因,我們若要想防禦該種攻擊,就需要從源頭抓起(用戶輸入),制定一套合理且安全的 XSS 過濾規則。
以下介紹一些過濾方法
-
對 HTML 標籤及一些特殊符號進行轉義
該種方法是一種非常簡單的過濾方法,僅僅是通過轉義的方式將一些 HTML 標籤和屬性轉義,比如 < 轉義成 < ;, 這樣像<script>xxx</script>的腳本就運行不了。當然簡單的過濾方式也就代表很容易就會被繞過。
另外如果需要使用含有富文本的功能時,使用這樣的過濾就會使富文本失去作用。 -
使用白名單、黑名單的方式進行過濾
白名單、黑名單顧名思義是要定義哪些東西是可通過的,哪些東西不可通過。比如常見 <b>、<p>; 、< 等等標籤,不可通過的比如 javascript、<a>、<script>、<iframe>、onload 等等一些屬性,將其進行轉義。
當然使用該種方法也有自身的缺點,你並不可能窮舉出所有元素,也可能會某些元素在黑名單內,但在某些情況它是需要使用的,這就需要我們在設計 XSS 過濾器的時候權衡好,取最合理最適合需求的設計。
總結
身爲一名 web 開發人員,應該去了解一下如何能夠進行 XSS 攻擊,這並不是要你去成爲一名黑客去攻擊別人的網站,去盜取別人的信息,而是去了解有哪些 XSS 攻擊場景,瞭解產生該漏洞的原因,從而去思考爲什麼會產生這個 bug,如何去修復這個 bug。要想設計出更好的 XSS 過濾器,就必須得知道有哪些攻擊方式,才能這樣思考更全面。
注:上面所寫的例子,在瀏覽器中運行不一定能成功,瀏覽器擁有自身的防禦機制,那麼簡單的攻擊方式,一般瀏覽器自身都已經會攔截了,了,如果你想真的測試的話,自己去 google 一下高級的 XSS 注入方式來學習吧
CSRF 攻擊
什麼是 CSRF
CSRF,全名:Cross site Request Forgery(跨站域請求僞造)。一般的攻擊方式是,通過請求僞造盜取用戶的 cookie 信息,進而進行操作。
CSRF 攻擊的原理
假設當前有用戶 A,服務器 B,服務器 C(含有惡意腳本)
- 首先用戶 A 請求登陸了服務器 B,這時服務器 B 響應了用戶 A,並且會返回唯一標識的該用戶的 cookie 信息。
- 用戶 A 在未退出服務器 B 時(即仍與服務器 B 保持會話狀態),訪問了帶有惡意腳本的服務器 C,服務器 C 響應給用戶 A 一個惡意頁面,並且通過惡意腳本僞裝用戶 A 向服務器 B 發送請求,此時服務器 B 誤以爲是用戶 A 請求,故響應並返回了用戶 A 的 cookie 信息。
- 服務器 C 收到用戶 A 與 服務器 B 的cookie 信息後,保存起來,並利用該信息僞裝成用戶 A 去訪問服務器 B,再進行相應的破壞(想幹嘛就幹嘛)
CSRF 漏洞產生的原因
其主要原因是服務器 B 沒有對請求的發起源進行合理的檢驗,即不加分析地認爲請求者一定是正常的用戶,就響應了用戶信息給非法分子。
如何去防禦 CSRF
下面提供兩種手段,從服務器端來防禦 CSRF
- 驗證 HTTP Referer 的值
- 使用請求令牌
驗證 HTTP Referer
熟悉 HTTP 協議的人都知道,HTTP 的頭部 有一個 Referer 信息的字段,它記錄着該次HTTP 請求的來源地址(即它從哪裏來的)。
既然 CSRF 攻擊僞造的請求是從服務器 C 發送過來的,那麼我們就禁止跨域訪問,在服務器端增加過濾器的過濾,過濾掉那些不是從本服務器 B 發出的請求,這樣可以在一定程度上避免 CSRF 攻擊。
但這也是有缺點的:
- 禁止別人跨域訪問你,那麼如果別人通過百度等搜索引擎來搜索你的時候,此時的 Referer 是 百度,服務器將認爲這是不被信任的,所以拒絕響應,這樣你的 web 應用就很難推廣了(這是我自己想的,我還沒測試過)
- 還有一點就是 Referer 的設置問題,雖然一般的瀏覽器都不允許修改該值,但仍然是存在舊版的瀏覽器可以修改的(比如 IE6),所以這還是存在一定的安全問題
使用請求令牌
該種方式是參考同步令牌所設計的,同步令牌是用於防止表單重複提交的場景。
請求令牌的工作方式:
- 用戶 A 訪問服務器 B
- 服務器 B 以某種隨機生成策略生成隨機字符串,並作爲令牌(token)保存在 session 裏面,然後夾帶着響應返回給用戶,並以隱藏域的形式保存在頁面中
- 用戶每次請求都會夾帶着 token 反饋給服務器
- 服務器接收到每次請求,都會先進行令牌驗證,若令牌驗證不通過,則認爲該次請求是非法的,拒絕響應。
由於 CSRF 是通過在服務器 C 上僞造請求的方式來訪問服務器 B,所以它是獲取不了頁面中的 token 字符串,所以在一定程度上是能防禦的。
總結
CSRF 攻擊是一種請求僞造的攻擊方式,它利用的是服務器不能識別用戶的類型從而盜取用戶的信息來攻擊。因此要防禦該種攻擊,因爲從服務器端着手,增強服務器的識別能力,設計良好的防禦機制。