# 網頁資訊安全處理筆記 ## SQL Injection >注入攻擊實作: >在 Textbox 內輸入字串內容 ` ' OR '1'='1 ` >或是 ` '; DROP TABLE Employees; ` **防範措施:** - 參數化查詢。而不是使用「組字串」的方式來執行SQL。 - 對輸入的數據進行驗證,以確保數據符合預期的格式或範圍。 >[什麼是 SQL Injection?該如何避免?](https://www.explainthis.io/zh-hant/swe/sql-injection) ## Poor Error Handling: Unhandled Exception 在程式碼中,應該改善錯誤處理,以避免未處理的例外情況,並提供更友好和有用的錯誤訊息。 **防範措施:** - 在程式碼中使用 try-catch 區塊,以捕獲可能發生的例外情況。 - 在 catch 區塊中,應該適當地記錄錯誤訊息,並向使用者提供有用的錯誤訊息,以便他們理解問題所在。 - 可以使用 ASP.NET 的全局錯誤處理事件(Application_Error)來捕獲未處理的例外情況,並將它們記錄下來或顯示自定義的錯誤頁面。 這些修改將幫助改善網頁伺服器的配置安全性和錯誤處理,使程式碼更堅固和安全。請按照上述建議進行修改後,重新審查程式碼並測試確保正常運作。 ## Cross-Site Scripting: Reflected 跨站腳本攻擊(Cross-Site Scripting, XSS):反射型 >黑箱掃描工具的攻擊實作: > >- `https://xxx.com/InventoryMgmt/Home/(A(WeBiNsPeCt))/Index` >- `https://xxx.com/InventoryMgmt/Home/(A())/Index` > >正常的網址應該是 > >- `https://xxx.com/InventoryMgmt/Home/Index` **防範措施:** 在 Global.asax.cs 內加入程式嗎 ```csharp= protected void Application_BeginRequest(object sender, EventArgs e) { // 到這時,Url 已被改成沒包含 SessionId // 但它的值會放在 Response._appPathModifier 變數之中 FieldInfo appPathModifierFieldInfo = Context.Response.GetType().GetField("_appPathModifier", BindingFlags.NonPublic | BindingFlags.Instance); object appPathModifier = appPathModifierFieldInfo.GetValue(Context.Response); if (appPathModifier != null) { // Url 中有 SessionId throw new HttpException(404, "Not found"); } // deny HTTP GET with request body if (Request.HttpMethod == "GET" && Request.ContentLength > 0) { throw new HttpException(403, "Forbidden"); } } ``` >- [為什麼 Url 中有 (A(XXXX)) 在 ASP.NET 中,卻不會噴 404 或是錯誤,反而回正常的頁面(200)呢?](https://rainmakerho.github.io/2020/11/11/aspnet-cookieless-url/) ## Reflected XSS All Clients 主要透過用戶發出惡意的請求,倘若後端沒有過濾而直接將結果回傳前端的話,就有可能執行到惡意的程式碼。 **防範措施:** ```csharp= using Ganss.Xss; // NuGet 加入 HtmlSanitizer 套件 #region XSS 的第一道防線:Sanitization (AntiXSS,HtmlSanitizer) /// <summary> /// 通過使用 HtmlSanitizer 來過濾輸入字串,再 HtmlEncode 以防止跨站腳本(XSS)攻擊。 /// </summary> public static string SanitizeHtmlEncode(string inputStr) { if (string.IsNullOrWhiteSpace(inputStr)) return string.Empty; var sanitizer = new HtmlSanitizer(); //sanitizer.AllowedAttributes.Add("class"); //sanitizer.AllowedAttributes.Add("id"); //sanitizer.AllowedSchemes.Add("mailto"); // 允許 <a href="mailto:" // 使用 HtmlSanitizer 進行消毒處理 (https://github.com/mganss/HtmlSanitizer) string sanitized = sanitizer.Sanitize(inputStr); string encoded = HttpUtility.HtmlEncode(sanitized); return encoded; } /// <summary> /// 在數據輸出到網頁時進行欄位內容過濾,以防止儲存型跨網站指令碼(Stored XSS)攻擊。 /// </summary> public static DataTable SanitizeHtmlEncodeInDataTable(DataTable dataTable) { foreach (DataRow row in dataTable.Rows) { foreach (DataColumn column in dataTable.Columns) { if (row[column] != DBNull.Value && !column.ReadOnly) { row[column] = SanitizeHtmlEncode(row[column].ToString()); } } } return dataTable; } #endregion XSS 的第一道防線:Sanitization (AntiXSS,HtmlSanitizer) ``` ## Reflected XSS Specific Clients **防範措施:** 同 Reflected XSS All Clients ## Stored XSS 被保存在資料庫中的 Javascript 引起的攻擊稱為 Stored XSS。 最常見的就是文章、留言等,因為用戶可以任意輸入內容,若沒有檢查,則 `<script>` 等標籤就會被視為正常的 HTML 做執行。 **防範措施:** Reflected XSS All Clients 的 `SanitizeHtmlEncodeInDataTable` 方法 ## Code Injection >漏洞描述: >用 Invoke 動態執行 Web service URL **防範措施:** 透過加入 Web 參考,以靜態的方式連線 Web service ## Cross-Frame Scripting >攻擊實作: >[Clickjacking 點擊劫持攻擊](https://blog.huli.tw/2021/09/26/what-is-clickjacking/) **防範措施:** - [X-Frame-Options](https://a42033.gitbooks.io/system/content/security/user/X_Frame_Options.html) ```xml <add name="X-Frame-Options" value="SAMEORIGIN" /> ``` - 內容安全策略(Content-Security-Policy, CSP) ```xml <add name="Content-Security-Policy" value="child-src 'self';" /> ``` ```xml! <add name="Content-Security-Policy" value="frame-ancestors 'self' tw.yahoo.com www.google.com;" /> ``` iframe_test.html 舉證、驗證 ```html= <!DOCTYPE html> <html> <head> <title>iframe test</title> </head> <body> <h1>iframe test</h1> <iframe src="要嵌入的網頁網址" width="600px" height="400px" frameborder="0" scrolling="no"></iframe> </body> </html> ``` ## HTML5: Missing Content Security Policy HTML5 引入了 Content-Security-Policy(CSP),這是一種用於增強網站安全性的機制。 當網站沒有設定 Content-Security-Policy 時,就稱為 Missing Content Security Policy。 **防範措施:** - [內容安全策略(Content-Security-Policy, CSP)](https://content-security-policy.com/) >Google 提供的網站:[CSP Evaluator](https://csp-evaluator.withgoogle.com/),它會偵測你的 CSP 是否有錯誤,以及是不是安全。 > >[XSS 防禦 - CSP script-src 設定](https://blog.darkthread.net/blog/csp-script-src/) ## HTML5: Overly Permissive Message Posting Policy HTML5 的新機制 Message Posting Policy 主要是指跨文件通訊的設定規則。這個機制允許使用 Script 腳本在不同窗口或框架之間傳送消息。在設定這個機制時,使用者可以指定目標窗口的來源,以確保只有特定合法來源的窗口才能接收消息。 當 Message Posting Policy 過於寬鬆時,也就是認為了使用不當而導致安全風險的情況下,就稱為 Overly Permissive Message Posting Policy。 JavaScript/TypeScript: ```javascript o.contentWindow.postMessage(message, '*'); ``` 使用 `*` 做為目標來源值,代表 Script 會傳送訊息至視窗而不論其來源。 **防範措施:** - 不要使用萬用字元 `*`,改為指定目標窗口的來源。 ## HTML5: CORS Functionality Abuse 同 Cache Management: Headers ## Web Server Misconfiguration: Insecure Content-Type Setting **防範措施:** ```xml <add name="X-Content-Type-Options" value="nosniff" /> ``` ## Insecure Transport: HSTS not Set HTTP Strict-Transport-Security 回應標頭 (HSTS) 告知瀏覽器該站點應僅使用 HTTPS 訪問,並且所有將來的 HTTP 訪問應自動轉換為 HTTPS。 **防範措施:** ```xml <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" /> ``` ## ASP.NET Misconfiguration: Missing Error Handling Web.config 檢測到 ```xml <customErrors mode="Off" /> ``` **防範措施:** ```xml <customErrors mode="On" defaultRedirect="Errors/ErrorPage.aspx"> <error statusCode="404" redirect="Errors/NotFound.aspx" /> <error statusCode="500" redirect="Errors/ServerError.aspx" /> </customErrors> ``` ## Compliance Failure: Missing Privacy Policy 對掃描範圍內可存取的所有網頁進行採樣,以取得通常構成隱私權政策聲明的文字內容。 **解決方法:** - 新增隱私權政策(Privacy Policy)的靜態頁面。 ## Cache Management: Headers ```xml <!-- CORS_Origins 因應資訊安全「同源政策」,請加入主機網域網址(含開發機, 測試機, 正式機)。若未加入會顯示 HTTP ERROR 403 --> <add key="CORS_Origins" value="http://主機網域網址1, https://主機網域網址1, http://主機網域網址2, https://主機網域網址2" /> ``` ```csharp= protected void Application_BeginRequest(object sender, EventArgs e) { /** 修復資訊安全漏洞 * Cache Management: Headers * HTML5: CORS Functionality Abuse */ string cors_origins = ConfigurationManager.AppSettings["CORS_Origins"] ?? ""; // 允許的來源列表 var allowedOrigins = new List<string>(cors_origins.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); // 去除字串前後的空白 allowedOrigins = allowedOrigins.ConvertAll(o => o.Trim()); HttpContext context = HttpContext.Current; string origin = context.Request.Headers["Origin"]; // 如果是非跨域請求(沒有 Origin),跳過 CORS 驗證 if (string.IsNullOrEmpty(origin)) { return; // 直接返回,不執行 CORS 邏輯 } // 檢查來源 if (allowedOrigins.Contains(origin)) { // 設置 CORS 標頭 context.Response.AddHeader("Access-Control-Allow-Origin", origin); context.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); context.Response.AddHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); } else { context.Response.StatusCode = 403; // 禁止訪問 //Logger.Warn($"未授權的 CORS 來源: {origin}"); context.Response.End(); return; } // 處理 OPTIONS 方法 if (context.Request.HttpMethod == "OPTIONS") { context.Response.End(); } } ``` ## Cache Management: Insecure Policy 不安全的快取策略可能允許攻擊者進行內容欺騙或資訊竊取攻擊。 >瀏覽器 F12 進入開發人員畫面 => 選擇 Network => 選擇網頁名稱 >可看到 Response Headers 的 Cache-Control: 內容為 no-cache, no-store **防範措施:** - ASP.NET MVC 在 Global.asax.cs 內加入 ```csharp= protected void Application_PreSendRequestHeaders(object sender, EventArgs e) { HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache); HttpContext.Current.Response.Cache.SetNoStore(); } ``` - ASP.NET WebForms 在 Web.config 內加入 ```xml= <system.webServer> <httpProtocol> <customHeaders> <add name="Cache-Control" value="no-cache, no-store, must-revalidate" /> <add name="Pragma" value="no-cache" /> <add name="Expires" value="0" /> </customHeaders> </httpProtocol> </system.webServer> ``` ## HTML5: Cross-Site Scripting Protection **防範措施:** ```xml <add name="X-XSS-Protection" value="1; mode=block" /> ``` ## Web Server Misconfiguration: Server Error Message Web 伺服器配置不當(Web Server Misconfiguration)是指在設置和管理 Web 伺服器(如 IIS)時出現的錯誤或不正確的配置。 比如 HTTP Response Headers 配置。 ## CSRF >[零基礎資安系列(一)-認識 CSRF(Cross Site Request Forgery)](https://tech-blog.cymetrics.io/posts/jo/zerobased-cross-site-request-forgery/) >想像你到一家餐廳吃飯,陌生人`(駭客)`拿了一張有你桌號的菜單`(Request)`點餐之後給老闆`(Server)`,結果老闆問也不問便收了菜單並將帳記到了你的身上,這就是 CSRF 的基礎概念。 >[如何防範?](https://www.explainthis.io/zh-hant/swe/what-is-csrf#csrf-%E9%98%B2%E7%A6%A6%E6%96%B9%E6%B3%95) >1. 加上驗證 >2. 不要用 `GET` 請求來做關鍵操作 >3. 檢查 Referrer >4. 使用 CSRF token >5. 瀏覽器本身防護 - SameSite cookies **實際的防範措施:** - 不要使用 `GET` 請求來做關鍵操作 ```csharp= if (!IsPostBack) { } else { // CSRF 防護:限制僅接受 POST 請求,防止 GET 請求觸發狀態變更。 if (Request.HttpMethod != "POST") { throw new InvalidOperationException($"資訊安全:{Request.HttpMethod} 為不允許的請求方法。僅接受 POST 請求。"); } } ``` - 調整程式碼執行流程 ```csharp= //string logonid = HttpUtility.HtmlEncode(Request.QueryString["logonid"] ?? ""); if (!IsPostBack) { string logonid = HttpUtility.HtmlEncode(Request.QueryString["logonid"] ?? ""); string NTUser = Utility.DecryptNTUser(logonid); ``` ## Data Filter Injection 使用 DataTable.Select 方法進行查詢時,當查詢條件是通過**字符串拼接**產生的(如 "ID='" + id + "'"),就存在 Data Filter Injection 的風險。 >攻擊場景: >假設攻擊者將 id 設置為 `1' OR '1'='1`. >查詢語句將被解析為:ID='1' OR '1'='1',這樣會返回所有行,從而泄露不應該訪問的數據。 ```csharp= // 資訊安全漏洞:Data Filter Injection //DataRow[] dr = dt.Select("ID='" + id + "'"); // 修復:改用 LINQ 查詢 DataRow[] dr = dt.AsEnumerable() .Where(r => r.Field<decimal>("ID").ToString() == id) .ToArray(); ``` ## Persistent Connection String ## Client Potential XSS **防範措施:** - 前端使用 [DOMPurify](https://github.com/cure53/DOMPurify) 避免 XSS 攻擊 ```javascript= $('.inject-defense').each(function () { var inputVal = $(this).val(); if (inputVal) { var cleanHTML = DOMPurify.sanitize(inputVal, { USE_PROFILES: { html: false } }); $(this).val(cleanHTML); } }); ``` ## Privacy Violation: Autocomplete **防範措施:** `<asp:TextBox>` 和 `<input type="text">` 的元素都加上 `autocomplete="off"` ## Privacy Violation >[Checkmarx | 使用 DefaultRequestHeaders.Authorization 卻被 Checkmarx 判斷有 Privacy Violation 的 Issue](https://rainmakerho.github.io/2022/11/25/checkmarx-headers-authorization-privacy-violation/) **防範措施:** 將變數名稱 `string userAccount` 調整成 `string user`。 ## Insufficient Connection String Encryption ## Path Traversal/Stored Path Traversal ```csharp= XmlReaderSettings settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Prohibit, // 禁用 DTD XmlResolver = null, // 禁用外部資源解析 IgnoreWhitespace = true, // 忽略空白 IgnoreComments = true // 忽略註解 }; XmlDocument xmlDoc = new XmlDocument(); using (var reader = XmlReader.Create(new StringReader(vendorData), settings)) { xmlDoc.Load(reader); } ``` ## Missing HSTS Header HTTP Strict-Transport-Security 回應標頭 (HSTS) 告知瀏覽器該站點應僅使用 HTTPS 訪問,並且所有將來的 HTTP 訪問應自動轉換為 HTTPS。 **防範措施:** ```xml <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" /> ``` ## SSL Verification Bypass >```csharp >ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; >``` > >這段程式碼會禁用所有 SSL 憑證的驗證,無論伺服器的憑證是否可信都會自動接受。這可能導致攻擊者進行中間人攻擊 (MITM),攔截和篡改 HTTPS 傳輸中的敏感資料。 **修復方法:** 移除不安全的憑證驗證邏輯 ```csharp ServicePointManager.ServerCertificateValidationCallback = null; ``` ## Often Misused: File Upload **防範措施:** - 前端對上傳的檔案進行副檔名限制 ```html <asp:FileUpload ID="oFileUpload" runat="server" accept=".xlsx,.xls" /> ``` - 後端對上傳的檔案進行副檔名、content-type 檢查 ```csharp= // 取得檔案副檔名 string fileExtension = Path.GetExtension(oFileUpload.FileName); // 取得 MIME 類型 string contentType = oFileUpload.PostedFile.ContentType; if (fileExtension.ToLower() != ".xls" && fileExtension.ToLower() != ".xlsx" && contentType != "application/vnd.ms-excel" && contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { Utility.Alert("僅允許上傳 Excel (.xls, .xlsx) 檔案。", this, false); return; } ```