[C#] 在網頁專案中使用 HtmlSanitizer 來防範 XSS 攻擊

2024-08-27

在做網頁專案中,很常會使用到 summernote 或是其他的 html 編輯器套件,會讓客戶輸入他自己要輸入的 html 

但是呢為了避免客戶輸入的 的程式碼造成 XSS 攻擊,所以有些 Tag 或是 Attribute 是危險的,這時候有同事推薦這個套件

HtmlSanitizer




1. 你可以透過 nuget 下載該套件 https://www.nuget.org/packages/HtmlSanitizer/

2. 這邊我的們案例 這是我們測試的 html code

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.css" /> <p>今天分享目前找到的圖床最後一篇,這服務比較特別,他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服務</p> <p>就是 <a href="https://www.pinata.cloud/" target="_blank">Pinata</a> <img src="https://i.imgur.com/GL2jlvp.png" style="max-width: 900px;" /> <script src="https://gist.github.com/donma/f93025193e3827f87eec33fccf34a824.js"></script> <script>alert('測試執行');</script> </p>


2.1 我們先測試預設什麼都不設定的狀況下他篩選掉什麼了,基本上 css,script 這些高危險的都被拿掉了

var sanitizer = new HtmlSanitizer(); var html = "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.css\" />" + "<p>今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服" + "務</p>\r\n<p>就是 <a href="\&quot;https://www.pinata.cloud/\&quot;" target="\&quot;_blank\&quot;">Pinata</a><img src="\&quot;https://i.imgur.com/GL2jlvp.png\&quot;" style="\&quot;max-width:" />" + "<script src=\"https://gist.github.com/donma/f93025193e3827f87eec33fccf34a824.js\"></script><script>alert('測試執行');</script></p>"; string sanitizedOutput = sanitizer.Sanitize(html); Console.WriteLine(sanitizedOutput); /* Result: <p>今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服務</p> <p>就是 <a href="https://www.pinata.cloud/" target="_blank">Pinata</a> <img src="https://i.imgur.com/GL2jlvp.png" style="max-width: 900px"></p> */


2.2 這時候我需要改變需求,我需要 script 這個 tag 這時候就可以自己手動加入

var sanitizer = new HtmlSanitizer(); var html = &quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.css\&quot; /&gt;&quot; + &quot;&lt;p&gt;今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服&quot; + &quot;務&lt;/p&gt;\r\n&lt;p&gt;就是 &lt;a href=\&quot;https://www.pinata.cloud/\&quot; target=\&quot;_blank\&quot;&gt;Pinata&lt;/a&gt;&lt;img src=\&quot;https://i.imgur.com/GL2jlvp.png\&quot; style=\&quot;max-width: 900px;\&quot; /&gt;&quot; + &quot;&lt;script src=\&quot;https://gist.github.com/donma/f93025193e3827f87eec33fccf34a824.js\&quot;&gt;&lt;/script&gt;&lt;script&gt;alert(&#39;測試執行&#39;);&lt;/script&gt;&lt;/p&gt;&quot;; sanitizer.AllowedTags.Add(&quot;script&quot;); string sanitizedOutputAlllowScript = sanitizer.Sanitize(html); Console.WriteLine(sanitizedOutputAlllowScript); /* Result: &lt;p&gt;今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服務&lt;/p&gt; &lt;p&gt;就是 &lt;a href=&quot;https://www.pinata.cloud/&quot; target=&quot;_blank&quot;&gt;Pinata&lt;/a&gt; &lt;img src=&quot;https://i.imgur.com/GL2jlvp.png&quot; style=&quot;max-width: 900px&quot;&gt; &lt;script src=&quot;https://gist.github.com/donma/f93025193e3827f87eec33fccf34a824.js&quot;&gt;&lt;/script&gt; &lt;script&gt;alert(&#39;測試執行&#39;);&lt;/script&gt;&lt;/p&gt; */


2.3 我需要用到 script 但是我不希望 在script 中 使用 src ,但是不能直接移除 src 這樣會影響到 img 下面的 src

var sanitizer = new HtmlSanitizer(); var html = &quot;&lt;link rel=\&quot;stylesheet\&quot; href=\&quot;https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.css\&quot; /&gt;&quot; + &quot;&lt;p&gt;今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服&quot; + &quot;務&lt;/p&gt;\r\n&lt;p&gt;就是 &lt;a href=\&quot;https://www.pinata.cloud/\&quot; target=\&quot;_blank\&quot;&gt;Pinata&lt;/a&gt;&lt;img src=\&quot;https://i.imgur.com/GL2jlvp.png\&quot; style=\&quot;max-width: 900px;\&quot; /&gt;&quot; + &quot;&lt;script src=\&quot;https://gist.github.com/donma/f93025193e3827f87eec33fccf34a824.js\&quot;&gt;&lt;/script&gt;&lt;script&gt;alert(&#39;測試執行&#39;);&lt;/script&gt;&lt;/p&gt;&quot;; sanitizer.AllowedTags.Add(&quot;script&quot;); // 使用 AngleSharp 解析和清理 HTML var config = Configuration.Default; var context = BrowsingContext.New(config); var document = context.OpenAsync(req =&gt; req.Content(html)).Result; // 遍歷所有的 &lt;script&gt; 標籤 foreach (var scriptElement in document.QuerySelectorAll(&quot;script&quot;)) { // 移除 src 屬性 scriptElement.RemoveAttribute(&quot;src&quot;); // 如果 &lt;script&gt; 標籤內部是空的&#65292;移除該標籤 if (string.IsNullOrWhiteSpace(scriptElement.TextContent)) { scriptElement.Remove(); } } string sanitizedOutputAllowScriptButSrc = sanitizer.Sanitize(document.DocumentElement.OuterHtml); Console.WriteLine(sanitizedOutputAllowScriptButSrc); /* Result: &lt;p&gt;今天分享目前找到的圖床最後一篇&#65292;這服務比較特別&#65292;他主打基於 Web 3 + IPFS 上儲存和檢索媒體的服務&lt;/p&gt; &lt;p&gt;就是 &lt;a href=&quot;https://www.pinata.cloud/&quot; target=&quot;_blank&quot;&gt;Pinata&lt;/a&gt; &lt;img src=&quot;https://i.imgur.com/GL2jlvp.png&quot; style=&quot;max-width: 900px&quot;&gt; &lt;script&gt;alert(&#39;測試執行&#39;);&lt;/script&gt; &lt;/p&gt; */


其中,部分有參考 ChatGPT 的程式碼,但是使用過程中 ChatGPT 一直叫我使用 PostProcessNode 來處理

但是卻沒有得到有效的結果,最後還是參考文件寫,就留在這邊筆記一下。




當麻許的碎念筆記 2014 | Donma Hsu Design.