安全測試基礎

一般來說,版本功能測試完成,對應的用例也實現了自動化,性能、兼容、穩定性測試也完成了以後,我們就需要考慮到系統的安全問題,特別是涉及到交易、支付、用戶賬戶信息的模塊,安全漏洞會帶來極高的風險。

 

一.安全測試原則與常見的安全威脅:

1.安全需求:

※認證:對認證的用戶的請求返回

※訪問控制:對未認證的用戶的權限控制和數據保護

※完整性:用戶必須準確的收到服務器發送的信息

※機密性:信息必須準確的傳遞給預期的用戶

※可靠性:失敗的頻率是多少?網絡從失敗中恢復需要多長時間?採取什麼措施來應對災難性的失敗?(個人理解這個地方應該更偏向於容錯容災測試的範疇)

※不可抵賴:用戶應該能證明接收到的數據來自特定的服務器

2.常見的安全測試內容

權限控制

SQL注入

URL安全測試

XSS(跨站腳本攻擊)

CSRF(跨站請求僞造)

URL跳轉漏洞

其他安全方面的考量

接下來,我們以一個C#實現的下常見的MVC架構網站爲例,來分析具體的各個安全測試角度。

 

二.權限控制

權限控制相對來說比較簡單,功能測試的過程中也接觸過不少,主要就是考慮以下方面:

1.用戶權限:我們假設存在兩個用戶A,B;其中A的權限級別很高,B的權限級別則很低:

只有A能進行的操作,B能不能進行操作;

只有A能看到的頁面,B能不能看到;

2.頁面權限:

必須登錄才能看到的頁面,不登錄直接訪問能否看到?

必須A-B-C的頁面,能否直接A-C?

通常來說單純的權限控制頁面測試不復雜,但是因爲權限控制和後續的URL跳轉、Session等方面結合的比較緊密,所以單獨提出來。

 

三.SQL注入

1.SQL注入原理

以Sql Sever爲例,C#提供了兩種操作數據庫的方法,以實現Sql Sever的查詢功能爲例(Mysql只需要將Sql對象替換爲MySql對象即可):

A.直接使用傳入的Sql進行數據庫操作:

複製代碼

  public static DataSet QuerySql(string sSql)
        {
            DataSet ds = new DataSet();
            try
            {
                Open();
                SqlDataAdapter mDataAdpter = new SqlDataAdapter(sSql, conn);
                mDataAdpter.Fill(ds);
            }
            catch (SqlException ex)
            {
                throw new Exception(ex.Message);
                DataBaseException = ex.Message;
            }
            finally
            {
                conn.Close();
            }
            return ds;
        }

複製代碼

 B.使用SqlParameter對象,對參數進行格式化,分離控制語句與執行語句:

複製代碼

   public static DataSet QuerySql(string sSql, SqlParameter[] Params)
        {
            DataSet ds = new DataSet();
            SqlCommand comm = new SqlCommand();
            try
            {
                Open();
                comm.Connection = conn;
                comm.CommandType = CommandType.Text;
                comm.CommandText = sSql;
                comm.Parameters.Clear();

                foreach (SqlParameter p in Params)
                {
                    comm.Parameters.Add(p);
                }
                SqlDataAdapter mAdapter = new SqlDataAdapter(comm);
                mAdapter.Fill(ds);
            }

            catch (SqlException ex)
            {
                DataBaseException = ex.Message;
                throw new Exception(ex.Message);
            }
            return ds;
        }

複製代碼

接下來我們來看以下場景:

用戶登錄,賬號密碼存在User表中,該表字段爲ID,Name,PassWord三個字段,驗證用戶登錄時直接傳用戶輸入的用戶名與密碼給數據庫,如果我們直接採用方式一,那麼代碼實現如下:

//獲取傳入的用戶UserName與PassWord

string sql = "SELECT * FROM User WHERE UserName = '"+UserName+"' AND PassWord = '"+PassWord+"'";

//其他處理代碼

假設我們的賬戶名稱是admin,密碼是123,那麼構造出的sql就是:

SELECT * FROM User WHERE UserName = ’admin’ AND PassWord = ’123’

執行結果看起來沒有問題,但是如果這個時候我們輸入的密碼是 ‘’or 1=1時,那麼實際執行的SQL就變成了:

SELECT * FROM User WHERE UserName = ’admin’ AND PassWord = '''' OR 1=1

(這裏輸入兩個分號是因爲構造sql的時候就已經是分號了,在sql sever中查詢的字符串中帶有分號則是需要再加一個分號進行轉義)

由於1=1恆等式的存在,這條sql會直接查詢出整個表的數據;就算沒有相關權限,服務器也會認爲是一個有效用戶進行處理。

如果我們再進一步,輸入密碼‘’or 1=1;drop table User

那麼結果會是什麼樣呢?User這個表會直接被刪除掉!這個時候網站就會因爲User表不存在而報錯,產生嚴重的異常。

綜上所述,SQL注入的原理就是通過構造符合SQL語法的參數傳入程序,通過執行SQL語句進而執行攻擊的操作;原因是程序完全信任了傳入的數據,致使非法數據能夠入侵系統。

 

2.解決方案:

在瞭解了SQL注入原理後,我們可以做出針對性的一些措施,如:

儘量避免使用動態構造SQL,而是使用SqlParameter對參數進行格式化或使用框架提供的一些功能,分離控制語句與執行語句;

對傳入的字符進行轉義處理,’和%、_、[]等通配符進行轉義處理,保證執行SQL的時候這些字符是正確在字符串內進行處理的;

在前端表單或控件中增加驗證,保證傳入後臺的數據是合法的;

數據庫權限控制,只給對應功能需要的權限,比如登錄頁面只能進行查詢,不賦予其執drop、update、delete、truncate等操作的權限。

 

四.URL安全測試:

1.MVC下的URL構成:

1).使用Get方式的URL構造方式:

~/控制器名/調用的方法?入參1=參數1&……&入參n=參數n,例如:

http://localhost:10344/AbnormalPunch/ApplySubmit?ID=13244&EmployeeID=1D2DE5AD8BC74E2A9CA70DE3567472EB

可以看到,在不經過處理的情況下,Get方式生成的URL可以看到數據和參數

2).使用Post方式的URL構造方式:、

~/控制器名/調用的方法,入參則放在報文實體主體部分中,例如:http://localhost:12688/Order/OrderList

通過接口測試手段可以獲取到訪問的入參:

{

    "OrderType": "0",

    "QueryType": "1"

}  

 

URL安全測試主要是基於URL的構成方式進行的測試,很多時候會涉及到和其他方向的交叉;瞭解各個原理後,就能比較全面的考慮問題了。

2.參數檢查:主要就是檢查URL或者主體報文中的參數

使用Get方式時,URL中顯示的參數正確;敏感參數如用戶名、密碼不應被顯示;

使用Post方式時,敏感參數應該進行加密處理

極端但是比較安全的處理方式是URL只顯示網站地址,

3.根據URL的構成方式直接篡改URL:

我們回過頭去看這個URL:

http://localhost:10344/AbnormalPunch/ApplySubmit?ID=13244&EmployeeID=1D2DE5AD8BC74E2A9CA70DE3567472EB

這個URL的內容是的查詢某個用戶提交的某個申請的明細,URL的傳入的ID爲要查詢的申請,EmployeeID是從Session中取的當前登錄用戶的ID。

那麼我們可以基於以下場景篡改URL進行驗證:

用戶未登錄時,直接輸入該網址進行訪問(涉及到登錄驗證);

其他用戶登錄時,輸入這個網址(涉及到權限控制)

構造ID和EmployeeID爲SQL注入的參數,然後訪問(涉及到SQL注入)

以及稍後會涉及到的XSS、Session、Cookie等場景。

 

五.XSS

跨站腳本攻擊(Cross Site Scripting),爲了和層疊樣式表css區分,簡寫爲XSS。

1.原理

攻擊者在網頁中嵌入客戶端腳本(例如JavaScript), 當用戶瀏覽此網頁時,腳本就會在用戶的瀏覽器上執行,從而達到攻擊者的目的。

例:

存在一個文本控件,其中value1from來自用戶的輸入:
<input type="text" name="address1" value="value1from">

直接輸入 "/><script>alert(document.cookie)</script><!-,那麼實際執行的語句:

<input type="text" name="address1" value=""/><script>alert(document.cookie)</script><!- ">

也可以將內容放到URL中進行訪問:

http://localhost:10344/AbnormalPunch/ApplySubmit?ID=<script>alert(document.cookie)</script>

我們可以看到,輸入的內容直接改變了程序的執行代碼,導致程序執行結果爲攻擊者想要的。

2.類型:   

反射型XSS:需要欺騙用戶進行操作才能觸發XSS代碼,主要威脅個體用戶

持久性XSS:代碼儲存在服務器中,用戶訪問時即可直接觸發XSS代碼,威脅大量用戶

3.解決思路:對數據進行html編碼處理,保證用戶輸入的數據不會改變程序代碼

 將重要的cookie標記爲http  only,這樣的話Javascript 中的document.cookie語句就不能獲取到cookie了.

只允許用戶輸入我們期望的數據。 例如: 年齡的textbox中,只允許用戶輸入數字。 而數字之外的字符都過濾掉。

過濾或移除特殊的Html標籤, 例如: <script>, <iframe> ,  &lt; for <, &gt; for >, &quot for

過濾JavaScript 事件的標籤。

4.XSS漏洞的測試:

A.查看代碼,驗證變量是否經過html編碼處理

B.準備測試腳本:

"/><script>alert(document.cookie)</script><!--

<script>alert(document.cookie)</script><!--

"onclick="alert(document.cookie)

遍歷TextBox或者其他文本控件,輸入這些測試腳本,如果瀏覽器彈出窗口且窗口內容爲cookie,證明存在XSS漏洞。

C.使用掃描工具如appscan

D.自行設計自動化測試腳本,用HttpWebRequest類,把包含xss 測試腳本發送給Web服務器,然後查看HttpWebResponse中,我們的XSS測試腳本是否已經注入進去了。

5.其他:

目前主流瀏覽器如Chrome、FireFox、IE8以上版本等都加入了安全機制用來過濾XSS;

ASP.NET中有防範XSS的機制,對提交的表單會自動檢查是否存在XSS,當用戶試圖輸入XSS代碼的時候,ASP.NET會拋出一個錯誤,暫時不清楚其他語言是否有這種機制。

 

六.CSRF

跨站請求僞造(Cross-Site Request Forgery),也被稱爲“One Click Attack”或者Session Riding,簡寫爲CSRF或XSRF。。儘管聽起來像跨站腳本(XSS),但它與XSS非常不同,並且攻擊方式幾乎相左。XSS利用站點內的信任用戶,而CSRF則通過僞裝來自受信任用戶的請求來利用受信任的網站。

1.CSRF的原理:CSRF可以理解爲攻擊者盜用了你的身份,以你的名義發送惡意請求,具體步驟如下:

1). 用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登錄網站A;

2).在用戶信息通過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登錄網站A成功,可以正常發送請求到網站A;

3). 用戶未退出網站A之前,在同一瀏覽器中,打開一個TAB頁訪問網站B;

4). 網站B接收到用戶請求後,返回一些攻擊性代碼,併發出一個請求要求訪問第三方站點A;

5). 瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的情況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求其實是由B發起的,所以會根據用戶C的Cookie信息以C的權限處理該請求,導致來自網站B的惡意代碼被執行。

 

 

因此,對於一個用戶來說,完成給CSRF攻擊必須要兩個步驟:

A.登錄受信任網站A,並在本地生成Cookie。

B 在不登出A的情況下,訪問危險網站B。

2.解決思路:

A.驗證 HTTP Referer 字段:

在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。在通常情況下,訪問一個安全受限頁面的請求來自於同一個網站;因此只需要驗證Referer的域名,驗證合法後再進行下一步操作。

然而,Referer 的值是由瀏覽器提供的,雖然 HTTP 協議上有明確的要求,但是每個瀏覽器對Referer的具體實現可能有差別,並不能保證瀏覽器自身沒有安全漏洞。對於某些瀏覽器,比如 IE6 或 FF2,目前已經有一些方法可以篡改 Referer 值。

B.在請求地址中添加 token 並驗證:

要抵禦 CSRF,關鍵在於在請求中放入黑客所不能僞造的信息,並且該信息不存在於cookie 之中。可以在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內容不正確,則認爲可能是 CSRF 攻擊而拒絕該請求。

C. 在 HTTP 頭中自定義屬性並驗證:

把它放到 HTTP 頭中自定義的屬性裏。通過 XMLHttpRequest 這個類,可以一次性給所有該類請求加上 csrftoken 這個 HTTP 頭屬性,並把 token 值放入其中。這樣解決了上種方法在請求中加入 token 的不便,同時,通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,也不用擔心 token 會透過 Referer 泄露到其他網站中去。

把它放到 HTTP 頭中自定義的屬性裏。通過 XMLHttpRequest 這個類,可以一次性給所有該類請求加上 csrftoken 這個 HTTP 頭屬性,並把 token 值放入其中。這樣解決了上種方法在請求中加入 token 的不便,同時,通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,也不用擔心 token 會透過 Referer 泄露到其他網站中去。

3.CSRF漏洞的測試:

A. 最簡單的方法就是抓取一個正常請求的數據包,去掉Referer字段後再重新提交,如果該提交還有效,那麼基本上可以確定存在CSRF漏洞。

B.使用相關工具進行測試:CSRFTester,CSRF Request Builder等;原理使用CSRFTester進行測試時,首先需要抓取我們在瀏覽器中訪問過的所有鏈接以及所有的表單等信息,然後通過在CSRFTester中修改相應的表單等信息,重新提交,這相當於一次僞造客戶端請求。如果修改後的測試請求成功被網站服務器接受,則說明存在CSRF漏洞,當然此款工具也可以被用來進行CSRF攻擊。

 

七. URL跳轉漏洞

1.實現原理:

服務端未對傳入的跳轉URL變量進行檢查和控制,可能導致可惡意構造任意一個惡意地址,誘導用戶跳轉到惡意網站。

一般來說,URL跳轉的測試方法爲修改參數中的合法URL爲非法URL,然後查看是否能正常跳轉或者響應包是否包含了任意的構造URL。

2.測試方法:

修改參數中的合法URL爲非法URL,然後查看是否能正常跳轉或者響應包是否包含了任意的構造URL 

 

八.其他安全角度的考量

1.安裝包測試:對C/S端的程序,安裝包主要考慮反編譯、簽名、完整性、權限等

2.數據庫:對於數據庫中的敏感字段,如用戶名、密碼等應該進行加密處理後再存儲;Cookie等敏感信息也要考慮設置過期時間等;

3.日誌、配置文件中儘量不要包含敏感信息

4.賬戶安全:數據庫中的密碼加密存儲,傳輸的密碼加密,密碼多次輸入錯誤後進行鎖定,多設備登錄的處理、註銷後的身份驗證等

5.結合實際版本需要的考量:比如一款電商APP,提交訂單接口時傳入了訂單信息和訂單總金額,支付接口根據提交訂單接口傳入的總金額進行支付;問題在於支付接口完全信任了訂單金額沒有做驗證,那麼可以直接調用訂單接口僞造金額從而以便宜的價格購物。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章