Fix #206
This commit is contained in:
@@ -58,9 +58,8 @@ namespace Ganss.XSS
|
|||||||
/// <param name="allowedAttributes">The allowed HTML attributes such as "href" and "alt". When <c>null</c>, uses <see cref="DefaultAllowedAttributes"/></param>
|
/// <param name="allowedAttributes">The allowed HTML attributes such as "href" and "alt". When <c>null</c>, uses <see cref="DefaultAllowedAttributes"/></param>
|
||||||
/// <param name="uriAttributes">The HTML attributes that can contain a URI such as "href". When <c>null</c>, uses <see cref="DefaultUriAttributes"/></param>
|
/// <param name="uriAttributes">The HTML attributes that can contain a URI such as "href". When <c>null</c>, uses <see cref="DefaultUriAttributes"/></param>
|
||||||
/// <param name="allowedCssProperties">The allowed CSS properties such as "font" and "margin". When <c>null</c>, uses <see cref="DefaultAllowedCssProperties"/></param>
|
/// <param name="allowedCssProperties">The allowed CSS properties such as "font" and "margin". When <c>null</c>, uses <see cref="DefaultAllowedCssProperties"/></param>
|
||||||
/// <param name="allowedCssClasses">CSS class names which are allowed in the value of a class attribute. When <c>null</c>, any class names are allowed.</param>
|
|
||||||
public HtmlSanitizer(IEnumerable<string> allowedTags = null, IEnumerable<string> allowedSchemes = null,
|
public HtmlSanitizer(IEnumerable<string> allowedTags = null, IEnumerable<string> allowedSchemes = null,
|
||||||
IEnumerable<string> allowedAttributes = null, IEnumerable<string> uriAttributes = null, IEnumerable<string> allowedCssProperties = null, IEnumerable<string> allowedCssClasses = null)
|
IEnumerable<string> allowedAttributes = null, IEnumerable<string> uriAttributes = null, IEnumerable<string> allowedCssProperties = null)
|
||||||
{
|
{
|
||||||
AllowedTags = new HashSet<string>(allowedTags ?? DefaultAllowedTags, StringComparer.OrdinalIgnoreCase);
|
AllowedTags = new HashSet<string>(allowedTags ?? DefaultAllowedTags, StringComparer.OrdinalIgnoreCase);
|
||||||
AllowedSchemes = new HashSet<string>(allowedSchemes ?? DefaultAllowedSchemes, StringComparer.OrdinalIgnoreCase);
|
AllowedSchemes = new HashSet<string>(allowedSchemes ?? DefaultAllowedSchemes, StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -68,7 +67,7 @@ namespace Ganss.XSS
|
|||||||
UriAttributes = new HashSet<string>(uriAttributes ?? DefaultUriAttributes, StringComparer.OrdinalIgnoreCase);
|
UriAttributes = new HashSet<string>(uriAttributes ?? DefaultUriAttributes, StringComparer.OrdinalIgnoreCase);
|
||||||
AllowedCssProperties = new HashSet<string>(allowedCssProperties ?? DefaultAllowedCssProperties, StringComparer.OrdinalIgnoreCase);
|
AllowedCssProperties = new HashSet<string>(allowedCssProperties ?? DefaultAllowedCssProperties, StringComparer.OrdinalIgnoreCase);
|
||||||
AllowedAtRules = new HashSet<CssRuleType>(DefaultAllowedAtRules);
|
AllowedAtRules = new HashSet<CssRuleType>(DefaultAllowedAtRules);
|
||||||
AllowedCssClasses = allowedCssClasses != null ? new HashSet<string>(allowedCssClasses) : null;
|
AllowedClasses = new HashSet<string>(DefaultAllowedClasses, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -393,12 +392,17 @@ namespace Ganss.XSS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the allowed CSS classes.
|
/// The default allowed CSS classes.
|
||||||
|
/// </summary>
|
||||||
|
public static ISet<string> DefaultAllowedClasses { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the allowed CSS classes. If the set is empty, all classes will be allowed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The allowed CSS classes.
|
/// The allowed CSS classes. An empty set means all classes are allowed.
|
||||||
/// </value>
|
/// </value>
|
||||||
public ISet<string> AllowedCssClasses { get; private set; }
|
public ISet<string> AllowedClasses { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs after sanitizing the document and post processing nodes.
|
/// Occurs after sanitizing the document and post processing nodes.
|
||||||
@@ -675,9 +679,6 @@ namespace Ganss.XSS
|
|||||||
var oldStyleEmpty = string.IsNullOrEmpty(tag.GetAttribute("style"));
|
var oldStyleEmpty = string.IsNullOrEmpty(tag.GetAttribute("style"));
|
||||||
SanitizeStyle(tag, baseUrl);
|
SanitizeStyle(tag, baseUrl);
|
||||||
|
|
||||||
var checkClasses = AllowedCssClasses != null;
|
|
||||||
var allowedTags = AllowedCssClasses?.ToArray() ?? Array.Empty<string>();
|
|
||||||
|
|
||||||
// sanitize the value of the attributes
|
// sanitize the value of the attributes
|
||||||
foreach (var attribute in tag.Attributes.ToList())
|
foreach (var attribute in tag.Attributes.ToList())
|
||||||
{
|
{
|
||||||
@@ -689,9 +690,9 @@ namespace Ganss.XSS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (checkClasses && attribute.Name == "class")
|
if (AllowedClasses.Any() && attribute.Name == "class")
|
||||||
{
|
{
|
||||||
var removedClasses = tag.ClassList.Except(allowedTags).ToArray();
|
var removedClasses = tag.ClassList.Except(AllowedClasses).ToArray();
|
||||||
|
|
||||||
foreach (var removedClass in removedClasses)
|
foreach (var removedClass in removedClasses)
|
||||||
RemoveCssClass(tag, removedClass, RemoveReason.NotAllowedCssClass);
|
RemoveCssClass(tag, removedClass, RemoveReason.NotAllowedCssClass);
|
||||||
|
|||||||
@@ -91,12 +91,12 @@ namespace Ganss.XSS
|
|||||||
Regex DisallowCssPropertyValue { get; set; }
|
Regex DisallowCssPropertyValue { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the allowed CSS classes.
|
/// Gets or sets the allowed CSS classes. If the set is empty, all classes will be allowed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The allowed CSS classes.
|
/// The allowed CSS classes. An empty set means all classes are allowed.
|
||||||
/// </value>
|
/// </value>
|
||||||
ISet<string> AllowedCssClasses { get; }
|
ISet<string> AllowedClasses { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs after sanitizing the document and post processing nodes.
|
/// Occurs after sanitizing the document and post processing nodes.
|
||||||
|
|||||||
@@ -2548,7 +2548,7 @@ rl(javascript:alert(""foo""))'>";
|
|||||||
RemoveReason? reason = null;
|
RemoveReason? reason = null;
|
||||||
string removedClass = null;
|
string removedClass = null;
|
||||||
|
|
||||||
var s = new HtmlSanitizer(allowedAttributes: new[] { "class" }, allowedCssClasses: new[] { "good" });
|
var s = new HtmlSanitizer(allowedAttributes: new[] { "class" }) { AllowedClasses = { "good" } };
|
||||||
s.RemovingCssClass += (sender, args) =>
|
s.RemovingCssClass += (sender, args) =>
|
||||||
{
|
{
|
||||||
reason = args.Reason;
|
reason = args.Reason;
|
||||||
@@ -2567,7 +2567,7 @@ rl(javascript:alert(""foo""))'>";
|
|||||||
RemoveReason? reason = null;
|
RemoveReason? reason = null;
|
||||||
string attributeName = null;
|
string attributeName = null;
|
||||||
|
|
||||||
var s = new HtmlSanitizer(allowedAttributes: new[] { "class" }, allowedCssClasses: new[] { "other" });
|
var s = new HtmlSanitizer(allowedAttributes: new[] { "class" }) { AllowedClasses = { "other" } };
|
||||||
s.RemovingAttribute += (sender, args) =>
|
s.RemovingAttribute += (sender, args) =>
|
||||||
{
|
{
|
||||||
attributeName = args.Attribute.Name;
|
attributeName = args.Attribute.Name;
|
||||||
@@ -2942,7 +2942,7 @@ zqy1QY1kkPOuMvKWvvmFIwClI2393jVVcp91eda4+J+fIYDbfJa7RY5YcNrZhTuV//9k="">
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void AllowClassesTest()
|
public void AllowClassesTest()
|
||||||
{
|
{
|
||||||
var sanitizer = new HtmlSanitizer(allowedAttributes: new[] { "class" }, allowedCssClasses: new[] { "good" });
|
var sanitizer = new HtmlSanitizer(allowedAttributes: new[] { "class" }) { AllowedClasses = { "good" } };
|
||||||
|
|
||||||
var html = @"<div class=""good bad"">Test</div>";
|
var html = @"<div class=""good bad"">Test</div>";
|
||||||
var actual = sanitizer.Sanitize(html);
|
var actual = sanitizer.Sanitize(html);
|
||||||
@@ -2969,22 +2969,10 @@ zqy1QY1kkPOuMvKWvvmFIwClI2393jVVcp91eda4+J+fIYDbfJa7RY5YcNrZhTuV//9k="">
|
|||||||
Assert.Equal(@"<div class=""good"">Test</div>", actual);
|
Assert.Equal(@"<div class=""good"">Test</div>", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void RemoveClassAttributeIfNoAllowedClassesTest()
|
|
||||||
{
|
|
||||||
// Empty array for allowed classes = no classes allowed
|
|
||||||
var sanitizer = new HtmlSanitizer(allowedAttributes: new[] { "class" }, allowedCssClasses: Array.Empty<string>());
|
|
||||||
|
|
||||||
var html = @"<div class=""good bad"">Test</div>";
|
|
||||||
var actual = sanitizer.Sanitize(html);
|
|
||||||
|
|
||||||
Assert.Equal(@"<div>Test</div>", actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RemoveClassAttributeIfEmptyTest()
|
public void RemoveClassAttributeIfEmptyTest()
|
||||||
{
|
{
|
||||||
var sanitizer = new HtmlSanitizer(allowedAttributes: new[] { "class" }, allowedCssClasses: new[] { "other" });
|
var sanitizer = new HtmlSanitizer(allowedAttributes: new[] { "class" }) { AllowedClasses = { "other" } };
|
||||||
|
|
||||||
var html = @"<div class=""good bad"">Test</div>";
|
var html = @"<div class=""good bad"">Test</div>";
|
||||||
var actual = sanitizer.Sanitize(html);
|
var actual = sanitizer.Sanitize(html);
|
||||||
|
|||||||
Reference in New Issue
Block a user