2008-11-20 29 views
33

這是針對.NET的。 IgnoreCase已設置且MultiLine未設置。如何過濾除特定白名單之外的所有HTML標記?

通常我在正則表達式體面的,也許我跑低咖啡因...

用戶被允許進入的HTML編碼實體(< LT ;,<安培;等),和使用以下HTML標籤:

u, i, b, h3, h4, br, a, img 

自動關閉< BR/>和< IMG/>是允許的,有或沒有額外的空間,但不是必需的。

我想:

  1. 地帶所有的開始和結束除上述列出的HTML標籤。
  2. 從其餘標籤中刪除屬性除了錨可以有一個href。

我的搜索模式(用空字符串替換)至今:

<(?!i|b|h3|h4|a|img|/i|/b|/h3|/h4|/a|/img)[^>]+> 

似乎是剝離所有我想要的開始和結束標記,但有三個問題:

  1. 必須包含每個允許標記的結束標記版本是醜陋的。
  2. 屬性存活。這可以發生在一個單一的替代?
  3. 標籤開頭,允許的標籤名稱通過。例如,「<縮寫>」和「<iframe>」。

以下建議的模式不會去掉沒有屬性的標籤。

</?(?!i|b|h3|h4|a|img)\b[^>]*> 

如下文所述,「>」是屬性值的法律,但它肯定地說,我不會支持。另外,不會有CDATA塊等問題。只是一個小小的HTML。

漏洞的答案是迄今爲止最好的答案,謝謝!下面是他的模式(希望的PRE更好地工作對我來說):

static string SanitizeHtml(string html) 
{ 
    string acceptable = "script|link|title"; 
    string stringPattern = @"</?(?(?=" + acceptable + @")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:([""']?).*?\1?)?)*\s*/?>"; 
    return Regex.Replace(html, stringPattern, "sausage"); 
} 

一些小的調整,我認爲仍然可以對這個回答讓:

  1. 我認爲這可能被修改,以獲取簡單的HTML通過將「! - 」添加到「可接受的」變量並對錶達式的末尾進行小的更改以允許可選的尾隨「\ s--」,來評論(本身不包含標籤的評論)。

  2. 我認爲如果在屬性之間存在多個空白字符(例如:帶有換行符和屬性之間的製表符的大量格式的HTML),這會中斷。

編輯2009-07-23:下面是最終的解決方案我(在VB.NET)去:

Dim AcceptableTags As String = "i|b|u|sup|sub|ol|ul|li|br|h2|h3|h4|h5|span|div|p|a|img|blockquote" 
Dim WhiteListPattern As String = "</?(?(?=" & AcceptableTags & _ 
     ")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:([""']?).*?\1?)?)*\s*/?>" 
html = Regex.Replace(html, WhiteListPattern, "", RegExOptions.Compiled) 

需要說明的是,標籤的HREF屬性仍然得到擦洗,這並不理想。

+0

請刪除不必要的[常規]標籤 – 2008-11-28 14:54:47

+0

你有沒有運氣消除屬性?漏洞的答案似乎沒有做到這一點? – russau 2009-07-23 02:35:33

回答

26

這裏有一個功能我寫了這個任務:

static string SanitizeHtml(string html) 
{ 
    string acceptable = "script|link|title"; 
    string stringPattern = @"</?(?(?=" + acceptable + @")notag|[a-zA-Z0-9]+)(?:\s[a-zA-Z0-9\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>"; 
    return Regex.Replace(html, stringPattern, "sausage"); 
} 

編輯:出於某種原因,我發佈了修正我的以前的答案作爲一個單獨的答案,所以我在這裏鞏固他們。

我會解釋一下正則表達式,因爲它有點長。

第一部分匹配一個打開的括號和0或1個斜槓(如果它是一個關閉標記)。

接下來,您將看到一個if-then構造和前瞻。 (?(?= SomeTag)then | else)我正在檢查字符串的下一部分是否是可接受標記之一。您可以看到,我將正則表達式字符串與可接受的變量連接起來,這是可以接受的標籤名稱,由一個垂直條分隔,以便任何條件都匹配。如果它是匹配的,你可以看到我放入了「notag」這個詞,因爲沒有標籤可以匹配,如果可以接受,我想讓它獨立。否則,我移動到else部分,在那裏我匹配任何標籤名稱[az,AZ,0-9] +

接下來,我想匹配0個或更多的屬性,我假設它們的形式爲attribute =「值」。所以現在我將這個部分分組來表示一個屬性,但是我使用了?:來防止這個組被速度捕獲:(?:\ s [az,AZ,0-9, - ] + =?(?:([ 「),']?)?\ 1?))

這裏我將從標記和屬性名稱之間的空格字符開始,然後匹配屬性名稱:[az,AZ,0-9 , - ] +

接下來我匹配一個等號,然後引用。我對報價進行分組,以便將其捕獲,並且我可以在後面執行反向引用\ 1以匹配相同類型的報價。在這兩個引號之間,你可以看到我使用期間來匹配任何東西,但是我使用懶惰版本*?而不是貪婪的版本*,以便它只匹配到可以結束此值的下一個報價。

接下來我們在括號之後加上一個*,以便它將匹配多個attirbute /值組合(或沒有)。最後,我們用\ s匹配一些空格,並在xml樣式自閉標籤的標籤中使用0或1個結尾斜槓。

你可以看到我用香腸替換了標籤,因爲我很餓,但是你可以用空字符串代替它們,以便將它們清除。

2

屬性是使用正則表達式嘗試使用HTML的主要問題。考慮潛在屬性的絕對數量,以及它們中的大多數是可選屬性以及它們可以以任何順序出現的事實,並且「>」是引用屬性值中的合法字符。當你開始嘗試考慮所有這些時,你需要處理的正則表達式很快就會變得難以管理。

我想要做的是使用基於事件的HTML解析器,或者爲您提供可以穿過的DOM樹。

10

這是HTML標記過濾良好的工作例如:

Sanitize HTML

+0

RefactorMyCode網站已停用一段時間。我相信它不再在服務中。 – sohtimsso1970 2012-08-22 12:14:37

+0

@ sohtimsso1970,是的,直到現在我還沒有注意到,這裏是2010年9月的存檔網頁:http://web.archive.org/web/20100901160940/http://refactormycode.com/codes/333-sanitize- html – CMS 2012-08-23 17:57:22

+0

查看代碼,這是我在這裏看到的最正確,最正確的正則表達式答案。我看不到任何直接的缺陷,儘管我會建議不要試圖用正則表達式來清理HTML。 – 2016-06-23 10:00:08

1

的原因,加上字邊界\ B沒有工作,你沒有把它超前裏面。因此,如果<啓動HTML標記,\ b將嘗試在<之後始終匹配。

把它放在裏面先行像這樣:

<(?!/?(i|b|h3|h4|a|img)\b)[^>]+> 

這也說明了如何把/標籤的列表之前,而不是與每個標籤。

0

我想我最初的目的是讓數值可選,但沒有按照,因爲我可以看到,我在等號後加了一個?,並將匹配的值部分分組。讓我們在該組之後添加一個?(用carot標記),以使其在比賽中可選。我不是在我的編譯器的權利,但看看,如果這個工程:

@"</?(?(?=" + acceptable + @")notag|[a-z,A-Z,0-9]+)(?:\s[a-z,A-Z,0-9,\-]+=?(?:(["",']?).*?\1?)?)*\s*/?>"; 
                          ^
2

我剛剛注意到目前的解決方案允許標籤開頭的任何可接受標籤。因此,如果「b」是可接受的標籤,則「閃爍」也是。沒有什麼大不了的,但是如果你對如何過濾HTML有嚴格要求,可以考慮一下。你當然不希望允許「s」作爲可接受的標籤,因爲它會允許「腳本」。

1
/// <summary> 
    /// Trims the ignoring spacified tags 
    /// </summary> 
    /// <param name="text">the text from which html is to be removed</param> 
    /// <param name="isRemoveScript">specify if you want to remove scripts</param> 
    /// <param name="ignorableTags">specify the tags that are to be ignored while stripping</param> 
    /// <returns>Stripped Text</returns> 
    public static string StripHtml(string text, bool isRemoveScript, params string[] ignorableTags) 
    { 
     if (!string.IsNullOrEmpty(text)) 
     { 
      text = text.Replace("&lt;", "<"); 
      text = text.Replace("&gt;", ">"); 
      string ignorePattern = null; 

      if (isRemoveScript) 
      { 
       text = Regex.Replace(text, "<script[^<]*</script>", string.Empty, RegexOptions.IgnoreCase); 
      } 
      if (!ignorableTags.Contains("style")) 
      { 
       text = Regex.Replace(text, "<style[^<]*</style>", string.Empty, RegexOptions.IgnoreCase); 
      } 
      foreach (string tag in ignorableTags) 
      { 
       //the character b spoils the regex so replace it with strong 
       if (tag.Equals("b")) 
       { 
        text = text.Replace("<b>", "<strong>"); 
        text = text.Replace("</b>", "</strong>"); 
        if (ignorableTags.Contains("strong")) 
        { 
         ignorePattern = string.Format("{0}(?!strong)(?!/strong)", ignorePattern); 
        } 
       } 
       else 
       { 
        //Create ignore pattern fo the tags to ignore 
        ignorePattern = string.Format("{0}(?!{1})(?!/{1})", ignorePattern, tag); 
       } 

      } 
      //finally add the ignore pattern into regex <[^<]*> which is used to match all html tags 
      ignorePattern = string.Format(@"<{0}[^<]*>", ignorePattern); 
      text = Regex.Replace(text, ignorePattern, "", RegexOptions.IgnoreCase); 
     } 

     return text; 
    } 
相關問題