Blazor sanitize MarkupString
Asked Answered
J

1

6

I'm trying to sanitize content of MarkupString. Actually I created this (based from https://github.com/dotnet/aspnetcore/blob/574be0d22c1678ed5f6db990aec78b4db587b267/src/Components/Components/src/MarkupString.cs)

public struct MarkupStringSanitized
{
    public MarkupStringSanitized(string value)
    {
        Value = value.Sanitize();
    }

    public string Value { get; }

    public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);

    public override string ToString() => Value ?? string.Empty;
}

But render output isn't raw html. How should I implement MarkupStringSanitized to use

@((MarkupStringSanitized)"Sanitize this content")
Jell answered 21/3, 2020 at 10:56 Comment(4)
“But render output isn't raw html” – What do you mean with that?Dingle
I mean that the text is rendered as pure text and is not recognized as html i.sstatic.net/YAj3y.pngJell
Whats the problem with: Markdown.ToHtml(Text, pipeline)?Freetown
Pls ignore my comment... This is from an external library.Freetown
V
13

Couple of suggestions (Not necessarily for OP, but for anyone else looking to solve the problem):

  • You didn't provide the code that does the actual sanitization, so I'm going to state the (hopefully) obvious best practice and if you're following it, great. Do not use Regular Expressions (Regex) to parse HTML
  • Also, the Sanitize() method should follow the pattern of immutability in this case
  • I would suggest the following library Gans.XSS.HtmlSanitizer which is an active library and updated regularly.

The problem

Razor View Engine can doesn't know how to render a MarkupStringSanitized. Just because you duck typed a sanitized version of the same struct doesn't mean it can render it. To get this to render, you'll need to cast it to something it does know, MarkupString

Here's what happens when I used your HtmlSanitizedMarkup directly with no modifications.

@((MarkupStringSanitized)Content)

enter image description here

Working Example #1

Here's an example using my Markdown -> Html playground (fully tested and working):

enter image description here

MarkupStringSanitized.cs
public struct MarkupStringSanitized
{
    public MarkupStringSanitized(string value)
    {
        Value = Sanitize(value);
    }

    public string Value { get; }

    public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);

    public static explicit operator MarkupString(MarkupStringSanitized value) => new MarkupString(value.Value);

    public override string ToString() => Value ?? string.Empty;

    private static string Sanitize(string value)  {
        var sanitizer = new HtmlSanitizer();
        return sanitizer.Sanitize(value);
    }
}
MarkupStringSanitizedComponent.razor
@if (Content == null)
{
    <span>Loading...</span>
}
else
{
    @((MarkupString)(MarkupStringSanitized)Content)
}

@code {
    [Parameter] public string Content { get; set; }
}

That extra conversion though is ugly IMO. (maybe someone smarter than me can clean that up?)

Working example #2

Here I tried extending the MarkupString with an extension method. It looks a little better, but only a little.

MarkupStringExtensions.cs
public static class MarkupStringExtensions
{
    public static MarkupString Sanitize(this MarkupString markupString)
    {
        return new MarkupString(SanitizeInput(markupString.Value));
    }

    private static string SanitizeInput(string value)
    {
        var sanitizer = new HtmlSanitizer();
        return sanitizer.Sanitize(value);
    }
}
MarkupStringSanitizedComponent.razor
@if (Content == null)
{
    <span>Loading...</span>
}
else
{
    @(((MarkupString)Content).Sanitize())
}

@code {
    [Parameter] public string Content { get; set; }
}
Voltaism answered 21/3, 2020 at 12:46 Comment(3)
Right, I forgot to describe the sanitize method, but it is the same as yours that use gans antixss. I like both solutions, i will use the working example #2. Thank youJell
I have another solution incoming, it's more idiomatic of Blazor to put this in a component. I'll update the answer when it's complete so check back!Voltaism
This is actually great, thank you very much AdamDuley

© 2022 - 2024 — McMap. All rights reserved.