前段時間公司又一輪安全審查,要求對各專案進行安全掃描,排查漏洞并修復,手上有幾個歷史專案,要求在限定的時間內全部修復并提交安全報告,也不清楚之前是如何做的漏洞修復,這次使用工具掃描出來平均每個專案都還有大概100來個漏洞,這些漏洞包括SQL陳述句注入,C#后端代碼,XML檔案,以及前端HTML,JS代碼幾個方面,由于一些專案比較老舊,限定的時間又短,做大的改動如果測驗不到位,很難保證不出什么問題,所以做了一些應及處理,不過這些都不失為一種手段,下面就來對這次安全漏洞的處理做個總結,
公司的漏洞掃描分為兩個階段,第一個階段是用Fortify這個工具來掃描,檢查出漏洞,修復并出報告,第二個階段是用APPSCAN對線上代碼掃描,我們先來說說第一個階段Fortify工具掃描出來的漏洞如何處理,至于第二階段,后期做了再來補上,
1.SQL注入
這一類漏洞主要是針對一些SQL陳述句做動態拼接時,傳入一個特殊的非法字符,如 SELECT id,name FROM User WHERE deparment=1000 and {ConditionalExpression} 其中 {ConditionalExpression} 作為引數本想在查詢頁面做一些動態條件的拼接,這樣就會帶來SQL注入的風險,如果有人通過手段將 {ConditionalExpression} 引數的值 改成這樣呢 1=1 OR 2 >1 又或者 1=1 ; drop table deparment 呢這就是一個重大的安全事故了,
載SQL注入一般可以從這幾方面預防:
1.系統中連接資料庫的帳號分配合適的權限,一般業務系統中資料庫操作帳號,不要分配對數庫結構產生改變的權限如 CREATE TABLE ,DROP XXXX 等
2.對復雜的查詢使用存盤程序,預先定義好引數,在存盤程序中拼接SQL陳述句
3.盡量使用例如 SqlParmater 引數化傳值使之成為規范
4.對SQL陳述句或引數的值做特殊關鍵詞過濾
5.使用如MyBATIS,Hibernate ,等支持 SQL MAPPER 的 ORM框架
6.盡量避免SQL陳述句動態拼接 或用動態LINQ 替代
公司的專案大部分都用的MyBatis ORM框架做Mapper 映射,這次漏洞掃描 SQL注入方面還好,基本沒有在代碼中拼接SQL的,但有一點有個別幾處代碼 用的是ADO.NET 讀寫資料庫,其中在實體化Connection 物件的地方掃描出connectString 未做加密處理,后面改用專案中現有的資料庫操作類別庫來操作就沒再報漏洞了,
2.Path Manipulation 路徑篡改
這次在安全漏洞篩查和處理程序中出現最多的就是 Path Manipulation 路徑篡改,手上幾個專案中其中就有兩個專案用到靜態頁面生成,涉及到大量的檔案操作,如果不做處理會報很多漏洞,首先來說說我對Path Manipulation 漏洞的認識:通過代碼對系統上檔案的操作如果不設定白名單,黑名單的過濾檢查,是一種安全隱患,比如某個公共方法中用到了,System.IO.File.Delete(path) .NET 提供的檔案洗掉這個方法,path是通過引數傳遞的,如果不做檢查,在一些呼叫的地方,被人改成了系統某個關鍵檔案,可能直接系統崩潰,這就是一個天大的事情了,
對此類漏洞的修復措施一般做法如下:
1.設定白名單或黑名單
通常做法是設定白名單,危險不可列舉,我們可以認為哪些是安全的,把它們列入允許操作的清單
2.設定檔案夾安全權限
只對允許操作的檔案夾設定讀寫權限,切不可將整個站點關件夾權限設定可寫
處理Path Manipulation 路徑篡改 漏洞的.Net 示例代碼:
private static Dictionary<string,string> CreateFortifyDictionary() { Dictionary<string, string> fortifyDictionary = new Dictionary<string, string>(); for(char c1 = 'a'; c1 <= 'z'; c1++) { fortifyDictionary.Add(c1.ToString(), c1.ToString()); } for (char c2 = 'A'; c2 <= 'Z'; c2++) { fortifyDictionary.Add(c2.ToString(), c2.ToString()); } for (int c3 = 0; c3 < 10; c3++) { fortifyDictionary.Add(c3.ToString(), c3.ToString()); } fortifyDictionary.Add(".", "."); fortifyDictionary.Add(":", ":"); fortifyDictionary.Add("/", "/"); fortifyDictionary.Add(Separator, Separator); return fortifyDictionary; } public static string SecurityPathFilter(string path) { path = path.ToLower(); path = path.Replace("c:"+ Separator + "windows", ""); path = path.Replace("c:" + Separator + "program files", ""); path = path.Replace("c:" + Separator + "", ""); char[] characters = path.ToCharArray(); StringBuilder resultStringBuilder = new StringBuilder(); var dictionary = CreateFortifyDictionary(); foreach (Char character in characters) { string value = https://www.cnblogs.com/wxdongtt2007/p/string.Empty; if (dictionary.TryGetValue(character.ToString(), out value)) { resultStringBuilder.Append(value); } } return resultStringBuilder.ToString(); }
3.Cross-site Scripting:Persistent 跨站腳本攻擊
參考 XSS 的定義:傳送到 Web 瀏覽器的惡意內容通常采用 JavaScript 代碼片段的形式,但也可能會包含一些 HTML、Flash 或者其他任意一種可以被瀏覽器執行的代碼,基于 XSS 的攻擊手段花樣百出,幾乎是無窮無盡的,但通常它們都會包含傳輸給攻擊者的私人資料(如 Cookie 或者其他會話資訊),在攻擊者的控制下,指引受害者進入惡意的網路內容;或者利用易受攻擊的站點,對用戶的機器進行其他惡意操作,大致意思是說 由于頁面在接收引數的程序中,沒有進行引數的校驗,可能存在 引數中存在可執行代碼的漏洞,
處理辦法一般是對引數進行轉義加碼 .NET中 參考System.Web.HttpUtility.DLL 程式集,呼叫下面方法:
string str= System.Web.HttpUtility.HtmlEncode(html)
用到的地方需要 反轉義解碼:
string html= System.Web.HttpUtility.HtmlDecode(str);
4.System Information Leak 系統資訊泄露
顧名思義就是系統的內部資訊在泄漏了,給系統帶來安全隱患,什么意思呢?下面是摘抄的一段話:
當系統資料或除錯資訊通過套接字或網路連接使程式流向遠程機器時,就會發生外部資訊泄露,外部資訊泄露會暴露有關作業系統、完整路徑名、現有用戶名或組態檔位置的特定資料,從而使攻擊者有機可乘,它比內部資訊(攻擊者更難訪問)泄露更嚴重
就是我們系統的除錯資訊和例外捕獲資訊不能暴露出來,比如這段代碼Fortify 直接會檢測出漏洞,
try { // } catch(Exception ex) { System.Console.WriteLine(ex.Message); }
我們或可改成這樣來解決
try { // } catch(Exception ex) { //System.Console.WriteLine(ex.Message); logger.Logger("系統例外:"+ex.Message,ex); }
錯誤資訊不應直接拋給終端,交由日志去記錄,
引申一下在系統資訊泄露這方面一般采用措施:
1.IIS上發布站點時關閉Debug 遠程除錯模式
2.定義錯誤頁面規范錯誤提示資訊
3.自定義客戶端例外資訊類,消化內部例外資訊,記錄日志,過濾處理后拋給客戶端允許可到的例外資訊
參考如下示例:
<compilation debug="false" /> <customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly" xdt:Transform="Replace"> <error statusCode="500" redirect="InternalError.htm"/> <error statusCode="403" redirect="NoAccess.htm" /> <error statusCode="404" redirect="FileNotFound.htm" /> </customErrors>
其中mode 說明如下:
1. On 表示在本地和遠程用戶都會看到自定義錯誤資訊,
2. Off 禁用自定義錯誤資訊,本地和遠程用戶都會看到詳細的錯誤資訊,
3. RemoteOnly 表示本地用戶將看到詳細錯誤資訊,而遠程用戶將會看到自定義錯誤資訊
string message = ""; try { // } catch(WTSError ee) { // message = ee.OutMessage; logger.Logger("系統例外:" + ee.Message, ee); } catch(Exception ex) { message = "系統例外,錯誤型別未知"; //System.Console.WriteLine(ex.Message); logger.Logger("系統例外:"+ex.Message,ex); }
5. Non-Serializable Object Stored in Session 寫入Session 的物件不可被序列化
這次安全描程序中也報了很多這類漏洞,不清楚寫入Session 會話中的物件為什么都要可被序列化,“在session中保存的物件最好是序列化,不然很容易導致類轉換的時候發生例外”這是我找到最簡短的回答,根據我的理解大概是,Session物件在存盤和讀取的時候會自動序列化和反序列化,對于非類似于 Int,String等非一般資料型別復雜的資料結構物件存盤和讀取屬性和狀態時資料轉換容易出錯,
對于這類問題的處理可以參考如下:
例如下面這段會報漏洞的代碼:
Session["UserToken"] = "sessionObjectValue";
可以自定義一個Session存盤物件,標為可序例化,并實作ISerializable 介面
[Serializable] public class SessionObject : ISerializable { [OptionalField] private string data; public string Data { get { return data; } set { data =https://www.cnblogs.com/wxdongtt2007/p/ value; } } public SessionObject(string data) { this.data =https://www.cnblogs.com/wxdongtt2007/p/ data; } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Data", data); Type basetype = this.GetType().BaseType; MemberInfo[] mi = FormatterServices.GetSerializableMembers(basetype, context); for (int i = 0; i < mi.Length; i++) { //由于AddValue不能添加重名值,為了避免子類變數名與基類變數名相同,將基類序列化的變數名加上基類類名 info.AddValue(basetype.FullName + "+" + mi[i].Name, ((FieldInfo)mi[i]).GetValue(this)); } } }
然后在Session寫入和讀取時寫成這樣
1 //Session["UserToken"] = new SessionObject("sessionObjectValue"); 2 Session["UserToken"] = new SessionObject("sessionObjectValue"); 3 4 //string sessionObjectValue = https://www.cnblogs.com/wxdongtt2007/p/Session["UserToken"].ToString(); 5 string sessionObjectValue = https://www.cnblogs.com/wxdongtt2007/p/((SessionObject)Session["UserToken"]).Data;
6.File Separator 檔案分割符
不可避免描述中也出現了這些漏洞,一般在Window環境下,不會出現這類漏洞帶來的問題,如果你的系統可以要布署在Linux或Unix 環境下就有可能出現Bug了,這類問題是指在不同作業系統環境下檔案路徑的分割符號不一樣,如果這樣一個路徑:“C:\tmp\test.txt” Windows 環境是:“C:\tmp\test.txt ” Linux 環境是:"/tmp/test.txt" 為了兼顧不同作業系統環境建議使用 System.IO.Path.DirectorySeparatorChar 物件對于上面的路徑這樣組合:
"C:" + System.IO.Path.DirectorySeparatorChar + "tmp" + System.IO.Path.DirectorySeparatorChar + "test.txt"
類似的還有換行符:windows 下是 \r\n Linux 等其它系統下是 \n 在.NET 中使用 System.Environment.NewLine 物件,
7.Insecure Randomness 安全亂數
參考網路上的解釋:
不安全的亂數:電腦是一種具有確定性的機器,因此不可能產生真正的隨機性,偽亂數生成器 (PRNG) 近似于隨機演算法,始于一個能計算后續數值的種子,
PRNG 包括兩種型別:統計學的 PRNG 和密碼學的 PRNG,統計學的 PRNG 可提供有用的統計資料,但其輸出結果很容易預測,因此資料流容易復制,若安全性取決于生成數值的不可預測性,則此型別不適用,密碼學的 PRNG 通過可產生較難預測的輸出結果來應對這一問題,為了使加密數值更為安全,必須使攻擊者根本無法、或極不可能將它與真實的亂數加以區分,通常情況下,如果并未宣告 PRNG 演算法帶有加密保護,那么它有可能就是一個統計學的 PRNG,不應在對安全性要求較高的環境中使用,其中隨著它的使用可能會導致嚴重的漏洞(如易于猜測的密碼、可預測的加密密鑰、會話劫持攻擊和 DNS 欺騙),
就是我們一般使用的隨機函式并不是真正的隨機產生,具有一定的可推測性,可能帶來一些安全性問題,說實話此類問題不好處理涉及到密碼學,如果感興趣話可找找這方面的資料也可以先看看這篇文章 https://www.cnblogs.com/asxinyu/p/4301554.html,個人認為一般系統可以用GUID 的方案,
以上就是這次Fortify 安全掃描中遇到的幾種漏洞型別,通過上述的方法基本都已解決,記得其中還遇到一個獲取電腦域帳號呼叫C++ 類別庫方法非安全代碼執行漏洞,還好找到另一種不用呼叫C++類別庫的方法去替換,如果避免不了要呼叫C++類別庫里的方法,如果報此類漏洞不知能有什么好的辦法來處理,希望有這方面經驗的園友不吝告之,
本文參考和參考的地址如下:
1. https://www.cnblogs.com/eyesmoon/p/7421477.html Fortify掃描漏洞解決方案
2. https://blog.csdn.net/abcxy12336/article/details/52335490 針對Fortify工具掃描出幾大漏洞的解決辦法總結--1
3. https://www.cnblogs.com/asxinyu/p/4301554.html 開源Math.NET基礎數學類別庫使用(14)C#生成安全的亂數
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/16050.html
標籤:ASP.NET
