1. 程式人生 > >Web開發常見的幾個漏洞解決方法 ---SQL注入

Web開發常見的幾個漏洞解決方法 ---SQL注入

平時工作,多數是開發Web專案,由於一般是開發內部使用的業務系統,所以對於安全性一般不是看的很重,基本上由於是內網系統,一般也很少會受到攻擊,但有時候一些系統平臺,需要外網也要使用,這種情況下,各方面的安全性就要求比較高了,所以往往會交付給一些專門做安全測試的第三方機構進行測試,然後根據反饋的漏洞進行修復,如果你平常對於一些安全漏洞不夠了解,那麼反饋的結果往往是很殘酷的,迫使你必須在很多細節上進行修復完善。本文主要根據本人專案的一些第三方安全測試結果,以及本人針對這些漏洞問題的修復方案,介紹在這方面的一些經驗,希望對大家有幫助。

基本上,參加的安全測試(滲透測試)的網站,可能或多或少存在下面幾個漏洞:SQL注入漏洞、跨站指令碼攻擊漏洞、登陸後臺管理頁面、IIS短檔案/資料夾漏洞、系統敏感資訊洩露。

1、測試的步驟及內容

這些安全性測試,據瞭解一般是先收集資料,然後進行相關的滲透測試工作,獲取到網站或者系統的一些敏感資料,從而可能達到控制或者破壞系統的目的。

第一步是資訊收集,收集如IP地址、DNS記錄、軟體版本資訊、IP段等資訊。可以採用方法有:
  1)基本網路資訊獲取;
  2)Ping目標網路得到IP地址和TTL等資訊;
  3)Tcptraceroute和Traceroute 的結果;
  4)Whois結果;
  5)Netcraft獲取目標可能存在的域名、Web及伺服器資訊;
  6)Curl獲取目標Web基本資訊;
  7)Nmap對網站進行埠掃描並判斷作業系統型別;
  8)Google、Yahoo、Baidu等搜尋引擎獲取目標資訊;
  9)FWtester 、Hping3 等工具進行防火牆規則探測;
  10)其他。

第二步是進行滲透測試,根據前面獲取到的資料,進一步獲取網站敏感資料。此階段如果成功的話,可能獲得普通許可權。採用方法會有有下面幾種

  1)常規漏洞掃描和採用商用軟體進行檢查;
  2)結合使用ISS與Nessus等商用或免費的掃描工具進行漏洞掃描;
  3)採用SolarWinds對網路裝置等進行搜尋發現;
  4)採用Nikto、Webinspect等軟體對Web常見漏洞進行掃描;
  5)採用如AppDetectiv之類的商用軟體對資料庫進行掃描分析;
  6)對Web和資料庫應用進行分析;
  7)採用WebProxy、SPIKEProxy、Webscarab、ParosProxy、Absinthe等工具進行分析;
  8)用Ethereal抓包協助分析;
  9)用Webscan、Fuzzer進行SQL注入和XSS漏洞初步分析;
  10)手工檢測SQL注入和XSS漏洞;
  11)採用類似OScanner的工具對資料庫進行分析;
  12)基於通用裝置、資料庫、作業系統和應用的攻擊;採用各種公開及私有的緩衝區溢位程式程式碼,也採用諸如MetasploitFramework 之類的利用程式集合。
  13)基於應用的攻擊。基於Web、資料庫或特定的B/S或C/S結構的網路應用程式存在的弱點進行攻擊。
  14)口令猜解技術。進行口令猜解可以採用 X-Scan、Brutus、Hydra、溯雪等工具。

第三步就是嘗試由普通許可權提升為管理員許可權,獲得對系統的完全控制權。在時間許可的情況下,必要時從第一階段重新進行。採用方法

  1)口令嗅探與鍵盤記錄。嗅探、鍵盤記錄、木馬等軟體,功能簡單,但要求不被防病毒軟體發覺,因此通常需要自行開發或修改。
  2)口令破解。有許多著名的口令破解軟體,如 L0phtCrack、John the Ripper、Cain 等

以上一些是他們測試的步驟,不過我們不一定要關注這些過程性的東西,我們可能對他們反饋的結果更關注,因為可能會爆發很多安全漏洞等著我們去修復的。

2、SQL注入漏洞的出現和修復

 1)SQL注入定義:

  SQL注入攻擊是黑客對資料庫進行攻擊的常用手段之一。隨著B/S模式應用開發的發展,使用這種模式編寫應用程式的程式設計師也越來越多。但是由於程式設計師的水平及經驗也參差不齊,相當大一部分程式設計師在編寫程式碼的時候,沒有對使用者輸入資料的合法性進行判斷,使應用程式存在安全隱患。使用者可以提交一段資料庫查詢程式碼,根據程式返回的結果,獲得某些他想得知的資料,這就是所謂的SQL Injection,即SQL注入。

  SQL注入有時候,在地址引數輸入,或者控制元件輸入都有可能進行。如在連結後加入’號,頁面報錯,並暴露出網站的物理路徑在很多時候,很常見,當然如果關閉了Web.Config的CustomErrors的時候,可能就不會看到。

另外,Sql注入是很常見的一個攻擊,因此,如果對頁面引數的轉換或者沒有經過處理,直接把資料丟給Sql語句去執行,那麼可能就會暴露敏感的資訊給對方了。如下面兩個頁面可能就會被添加註入攻擊。

①HTTP://xxx.xxx.xxx/abc.asp?p=YY and (select top 1 name from TestD ... type='U' and status>0)>0 得到第一個使用者建立表的名稱,並與整數進行比較,顯然abc.asp工作異常,但在異常中卻可以發現表的名稱。假設發現的表名是xyz,則
②HTTP://xxx.xxx.xxx/abc.asp?p=YY and (select top 1 name from TestDB.dbo.sysobjects& ... tatus>0 and name not in('xyz'))>0 可以得到第二個使用者建立的表的名稱,同理就可得到所有用建立的表的名稱。

為了遮蔽危險Sql語句的執行,可能需要對進行嚴格的轉換,例如如果是整形的,就嚴格把它轉換為整數,然後在操作,這樣可以避免一些潛在的危險,另外對構造的sql語句必須進行Sql注入語句的過濾,如我的框架(Winform開發框架、Web開發框架等)裡面就內建了對這些有害的語句和符號進行清除工作,由於是在基類進行了過濾,因此基本上子類都不用關心也可以避免了這些常規的攻擊了。

複製程式碼
        /// <summary>
        /// 驗證是否存在注入程式碼(條件語句)
        /// </summary>
        /// <param name="inputData"></param>
        public bool HasInjectionData(string inputData)
        {
            if (string.IsNullOrEmpty(inputData))
                return false;

            //裡面定義惡意字元集合
            //驗證inputData是否包含惡意集合
            if (Regex.IsMatch(inputData.ToLower(), GetRegexString()))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 獲取正則表示式
        /// </summary>
        /// <returns></returns>
        private static string GetRegexString()
        {
            //構造SQL的注入關鍵字元
            string[] strBadChar =
            {
                //"select\\s",
                //"from\\s",
                "insert\\s",
                "delete\\s",
                "update\\s",
                "drop\\s",
                "truncate\\s",
                "exec\\s",
                "count\\(",
                "declare\\s",
                "asc\\(",
                "mid\\(",
                "char\\(",
                "net user",
                "xp_cmdshell",
                "/add\\s",
                "exec master.dbo.xp_cmdshell",
                "net localgroup administrators"
            };

            //構造正則表示式
            string str_Regex = ".*(";
            for (int i = 0; i < strBadChar.Length - 1; i++)
            {
                str_Regex += strBadChar[i] + "|";
            }
            str_Regex += strBadChar[strBadChar.Length - 1] + ").*";

            return str_Regex;
        }
複製程式碼

上面的語句用於判別常規的Sql攻擊字元,我在資料庫操作的基類裡面,只需要判別即可,如下面的一個根據條件語句查詢資料庫記錄的函式。

複製程式碼
        /// <summary>
        /// 根據條件查詢資料庫,並返回物件集合
        /// </summary>
        /// <param name="condition">查詢的條件</param>
        /// <param name="orderBy">自定義排序語句,如Order By Name Desc;如不指定,則使用預設排序</param>
        /// <param name="paramList">引數列表</param>
        /// <returns>指定物件的集合</returns>
        public virtual List<T> Find(string condition, string orderBy, IDbDataParameter[] paramList)
        {
            if (HasInjectionData(condition))
            {
                LogTextHelper.Error(string.Format("檢測出SQL注入的惡意資料, {0}", condition));
                throw new Exception("檢測出SQL注入的惡意資料");
            }

            ...........................
        }
複製程式碼

以上只是防止Sql攻擊的一個方面,還有就是堅持使用引數化的方式進行賦值,這樣很大程度上減少可能受到SQL注入攻擊。

            Database db = CreateDatabase();
            DbCommand command = db.GetSqlStringCommand(sql);
            command.Parameters.AddRange(param);

3、跨站指令碼攻擊漏洞出現和修復

 跨站指令碼攻擊,又稱XSS程式碼攻擊,也是一種常見的指令碼注入攻擊。例如在下面的介面上,很多輸入框是可以隨意輸入內容的,特別是一些文字編輯框裡面,可以輸入例如<script>alert('這是一個頁面彈出警告');</script>這樣的內容,如果在一些首頁出現很多這樣內容,而又不經過處理,那麼頁面就不斷的彈框,更有甚者,在裡面執行一個無限迴圈的指令碼函式,直到頁面耗盡資源為止,類似這樣的攻擊都是很常見的,所以我們如果是在外網或者很有危險的網路上釋出程式,一般都需要對這些問題進行修復。

XSS程式碼攻擊還可能會竊取或操縱客戶會話和 Cookie,它們可能用於模仿合法使用者,從而使黑客能夠以該使用者身份檢視或變更使用者記錄以及執行事務。
[建議措施]
清理使用者輸入,並過濾出 JavaScript 程式碼。我們建議您過濾下列字元:
[1] <>(尖括號)
[2] "(引號)
[3] '(單引號)
[4] %(百分比符號)
[5] ;(分號)
[6] ()(括號)
[7] &(& 符號)
[8] +(加號)

為了避免上述的XSS程式碼攻擊,解決辦法是可以使用HttpUitility的HtmlEncode或者最好使用微軟釋出的AntiXSSLibrary進行處理,這個更安全。

微軟反跨站指令碼庫(AntiXSSLibrary)是一種編碼庫,旨在幫助保護開發人員保護他們的基於Web的應用不被XSS攻擊。 

編碼方法

使用場景

示例

HtmlEncode(String)

不受信任的HTML程式碼。 <a href=”http://www.cnblogs.com”>Click Here [不受信任的輸入]</a>
HtmlAttributeEncode(String) 不受信任的HTML屬性

<hr noshade size=[不受信任的輸入]>

JavaScriptEncode(String)

不受信任的輸入在JavaScript中使用

<script type=”text/javascript”>

[Untrusted input]

</script>

UrlEncode(String) 不受信任的URL

<a href=”http://cnblogs.com/results.aspx?q=[Untrusted input]”>Cnblogs.com</a>

VisualBasicScriptEncode(String)

不受信任的輸入在VBScript中使用

<script type=”text/vbscript” language=”vbscript”>

[Untrusted input]

</script>

XmlEncode(String)

不受信任的輸入用於XML輸出

<xml_tag>[Untrusted input]</xml_tag>

XmlAttributeEncode(String) 不 受信任的輸入用作XML屬性

<xml_tag attribute=[Untrusted input]>Some Text</xml_tag>

        protected void Page_Load(object sender, EventArgs e)
        {
            this.lblName.Text = Encoder.HtmlEncode("<script>alert('OK');</SCRIPT>");
        }

例如上面的內容,賦值給一個Lable控制元件,不會出現彈框的操作。

但是,我們雖然顯示的時候設定了轉義,輸入如果要限制它們怎麼辦呢,也是使用AntiXSSLibrary裡面的HtmlSanitizationLibrary類庫Sanitizer.GetSafeHtmlFragment即可。

        protected void btnPost_Click(object sender, EventArgs e)
        {
            this.lblName.Text = Sanitizer.GetSafeHtmlFragment(txtName.Text);
        }

這樣對於特殊指令碼的內容,會自動剔除過濾,而不會記錄了,從而達到我們想要的目的。

4、IIS短檔案/資料夾漏洞出現和修復

 

通過猜解,可能會得出一些重要的網頁檔案地址,如可能在/Pages/Security/下存在UserList.aspx和MenuList.aspx檔案。

[建議措施]
1)禁止url中使用“~”或它的Unicode編碼。
2)關閉windows的8.3格式功能。

修復可以參考下面的做法,或者找相關運維部門進行處理即可。

5、系統敏感資訊洩露出現和修復

如果頁面繼承一般的page,而沒有進行Session判斷,那麼可能會被攻擊者獲取到頁面地址,進而獲取到例如使用者名稱等重要資料的。

一般避免這種方式是對於一些需要登入才能訪問到的頁面,一定要進行Session判斷,可能很容易給漏掉了。如我在Web框架裡面,就是繼承一個BasePage,BasePage 統一對頁面進行一個登入判斷。

    public partial class UserList : BasePage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
          ...............
複製程式碼
    /// <summary>
    /// BasePage 整合自許可權基礎抽象類FPage,其他頁面則整合自BasePage
    /// </summary>
    public class BasePage : FPage
    {
        /// <summary>
        /// 預設建構函式
        /// </summary>
        public BasePage()
        {
            this.IsFunctionControl = true;//預設頁面啟動許可權認證
        }

        /// <summary>
        /// 檢查使用者是否登入
        /// </summary>
        private void CheckLogin()
        {
            if (string.IsNullOrEmpty(Permission.Identity))
            {
                string url = string.Format("{0}/Pages/CommonPage/Login.aspx?userRequest={1}",
                    Request.ApplicationPath.TrimEnd('/'), HttpUtility.UrlEncode(Request.Url.ToString()));
                Response.Redirect(url);
            }
        }

        /// <summary>
        /// 覆蓋HasFunction方法以使許可權類判斷是否具有某功能點的許可權
        /// </summary>
        /// <param name="functionId"></param>
        /// <returns></returns>
        protected override bool HasFunction(string functionId)
        {
            CheckLogin();

            bool breturn = false;
            try
            {
                breturn = Permission.HasFunction(functionId);
            }
            catch (Exception)
            {
                Helper.Alerts(this, "BasePage呼叫許可權系統的HasFunction函數出錯");
            }
            return breturn;
        }

        protected override void OnInit(EventArgs e)
        {
            Response.Cache.SetNoStore(); //清除快取
            base.OnInit(e);

            CheckLogin();
        }
複製程式碼

否則可能會受到攻擊,並通過抓包軟體發現頁面資料,獲得一些重要的使用者名稱或者相關資訊。

還有一個值得注意的地方,就是一般這種不是很安全的網路,最好要求輸入比較複雜一點的密碼(強制要求),例如不能全部是數字密碼或者不能是純字元,對位數也要求多一點,因為很多人輸入12345678,123456,123這樣的密碼,很容易被猜出來並登入系統,造成不必要的損失。

6、總結性建議

針對上面發現的問題,提出下面幾條建議。

1)在伺服器與網路的介面處配置防火牆,用於阻斷外界使用者對伺服器的掃描和探測。
2)限制網站後臺訪問許可權,如:禁止公網IP訪問後臺;禁止服務員使用弱口令。
3)對使用者輸入的資料進行全面安全檢查或過濾,尤其注意檢查是否包含SQL 或XSS特殊字元。這些檢查或過濾必須在伺服器端完成。
4)關閉windows的8.3格式功能。
5)限制敏感頁面或目錄的訪問許可權。