程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> 簡單高效防注入攻擊的動態SQL語句拼接方法

簡單高效防注入攻擊的動態SQL語句拼接方法

編輯:關於SqlServer
  其實對與初學者來說,進行的動態的查詢語句拼接也不是那麼好做的事情,就是做出來了,也未必是經得起考驗的足夠靈活好用的,未必是能拿得出手可以進行推廣的,是否能拿得出就是其中的關鍵。

 

   今天檢查公司的軟件項目質量,發現有2個同事寫的程序存在SQL注入攻擊的漏洞,當然也不能怪罪人家,他們也是剛參加工作1-2年,還沒有那麼豐富的技術經驗、安全意識,不會注意到自己編寫的系統會有嚴重的安全漏洞。

   公司在寧波也有一個政府網站的項目,在做系統安全檢查自動掃描時,也被查出了一些SQL注入攻擊的漏洞,這也使得讓我更加提高了系統是否存在安全漏洞的意識,當然我寫的系統很少會有這類的漏洞,但是整個公司有幾十號人在做開發公司,所以也難免別人不會犯錯。

  

   人工檢查是否有SQL注入安全漏洞,其實非常簡單,只要在查詢輸入框裡輸入有單引號的字符“'”,例如查詢條件輸入“吉日'嘎拉”其中有單引號,很可能這個查詢的頁面就崩潰了出現了錯誤頁面,或者跳轉到出錯頁面了,若有這樣的情況發生,幾乎99.3721%都可以看做是有潛在的SQL注入攻擊漏洞。

   防止這個錯誤的發生,從技術上應該說是要用“參數化的查詢”,貼一些代碼,給大家參考一下我的做法:

代碼         #region public DataTable Search(string folderId, string searchValue, Boolean deleteMark) 查詢
        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="folderId">目錄</param>
        /// <param name="searchValue">查詢條件</param>
        /// <param name="deleteMark">刪除標志</param>
        /// <returns>數據表</returns>
        public DataTable Search(string folderId, string searchValue, Boolean deleteMark)
        {
            // 一、這裡是將Boolean值轉換為int類型。
            int delete = deleteMark ? 1: 0;

            // 二、這裡是開始進行動態SQL語句拼接,字段名、表明都進行了常量定義,表名字段名發生變化時,很容易就知道程序哪裡都調用了這些。
            string sqlQuery = string.Empty;
            sqlQuery = " SELECT " + BaseNewsTable.FIEldId
                    + "        ," + BaseNewsTable.FIEldFolderId
                    + "        ," + BaseNewsTable.FIEldTitle
                    + "        ," + BaseNewsTable.FIEldFilePath
                    + "        ," + BaseNewsTable.FIEldFileSize
                    + "        ," + BaseNewsTable.FIEldReadCount
                    + "        ," + BaseNewsTable.FIEldDescription
                    + "        ," + BaseNewsTable.FIEldCategoryCode
                    + "        ," + BaseNewsTable.FIEldEnabled
                    + "        ," + BaseNewsTable.FIEldDeleteMark
                    + "        ," + BaseNewsTable.FIEldSortCode
                    + "        ," + BaseNewsTable.FIEldCreateUserId
                    + "        ," + BaseNewsTable.FIEldCreateUserRealname
                    + "        ," + BaseNewsTable.FIEldCreateDate
                    + "        ," + BaseNewsTable.FIEldModifyUserId
                    + "        ," + BaseNewsTable.FIEldModifyUserRealname
                    + "        ," + BaseNewsTable.FIEldModifyDate
                    + " FROM " + this.CurrentTableName
                    + " WHERE " + BaseNewsTable.FIEldDeleteMark + " = " + delete;

            // 三、我們認為 folderId 這個查詢條件是安全,不是人為輸入的參數,所以直接進行了SQL語句拼接
            if (!String.IsNullOrEmpty(folderId))
            {
                sqlQuery += " AND " + BaseNewsTable.FIEldFolderId + " = '" + folderId + "'";
            }

            // 四、這裡是進行參數化的准備,因為是多個不確定的查詢參數,所以用了List。
            List<DbParameter> dbParameters = new List<DbParameter>();

            // 五、這裡看查詢條件是否為空
            searchValue = searchValue.Trim();
            if (!String.IsNullOrEmpty(searchValue))
            {
                // 六、這裡是進行支持多種數據庫的參數化查詢
                sqlQuery += " AND (" + BaseNewsTable.FIEldTitle + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FIEldTitle);
                sqlQuery += " OR " + BaseNewsTable.FIEldCreateUserRealname + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FIEldCreateUserRealname);
                sqlQuery += " OR " + BaseNewsTable.FIEldContents + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FIEldContents);
                sqlQuery += " OR " + BaseNewsTable.FIEldDescription + " LIKE " + DbHelper.GetParameter(BaseNewsTable.FIEldDescription) + ")";
                
                // 七、這裡是判斷,用戶是否已經輸入了%
                if (searchValue.IndexOf("%") < 0)
                {
                    searchValue = "%" + searchValue + "%";
                }

                // 八、這裡生成支持多數據庫的參數
                dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FIEldTitle, searchValue));
                dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FIEldCreateUserRealname, searchValue));
                dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FIEldContents, searchValue));
                dbParameters.Add(DbHelper.MakeInParam(BaseNewsTable.FIEldDescription, searchValue));
            }

            // 九、這裡是將List轉換為數組,進行數據庫查詢
            return DbHelper.Fill(sqlQuery, dbParameters.ToArray());
        }
        #endregion

 

對以上代碼進行一下簡單的點評:

優點有如下:

    1:支持多數據庫。

    2:dbParameters.Add,非常靈活,可以動態組織多個查詢條件條件,想要幾個參數就要幾個參數,最後又巧妙的用了 dbParameters.ToArray(),這個是值得學習的。

    3:函數的命名、注釋、參數的大小寫比較規范。

    4:函數的注釋寫得很棒,對初學者學習模仿起了一個好榜樣。

    5:searchValue.IndexOf("%") 也想得比較深入,有些專業人事查詢時,可能已經輸入了%。

    6:表名、表字段都進行了定義,若後期表名、表字段發生了變化,程序不會有未知的錯誤,很容易在編碼階段就發現錯誤,在軟件開發初期,表名、字段名變來變去是很常見的事情,若是好幾個人開發的,又經常變來變去的,若是當時沒控制好,後期就會亂套。

    7:SQL語句拼接時,沒有用 WHERE 1=1 AND , 而是巧妙的運用了 DeleteMark 字段,是值得學習的。

    8:SQL語句中關鍵字都進行了大寫,是比較符合行業規范的,大家也值得參考。

    9:不管如何,對自己寫的每行代碼,每行注釋,都有了深入的講解、深入的認識,這是大家值得學習的,若哪裡寫得不好,有錯就改的精神,分享的精神是值得學習的。

  10:先關注好身邊的事情、才能關注網上的事情,是大家值得學習的,別總是有過於遠大的理想,過於理想化的夢想,把身邊的事情都做好,把身邊的同事都關注好,就是干得最出色最及格了,這個務實的精神也是大家值得學習的。

  11:  查詢代碼思路嚴謹得有些過分,實在是過分,區區一個動態查詢居然分了9個步驟來實現,思路細膩嚴謹得讓人實在是佩服啊,不佩服不行啊,菜鳥程序員的驕傲、學習模仿的楷模,呵呵。

 

  先就寫到這裡吧,再誇下去,估計很多人都要吐了。

  相應的源碼給大家敬上,若能起到參考,我也很榮幸了

  /Files/jirigala/DotNet.CommonV3.0.rar

  /Files/jirigala/handbookV3.0.pdf

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved