How to protect against XSS in ASP.NET Core?

Viewed 21798

In ASP.NET we had Request Validation but in ASP.NET Core there is no such thing.

How can we protect an ASP.NET Core app against XSS in the best way?

Request validation gone: https://nvisium.com/resources/blog/2017/08/08/dude-wheres-my-request-validation.html

  • this guy recommmends RegEx on Models like:

    [RegularExpression(@"^[a-zA-Z0-9 -']*$", ErrorMessage = "Invalid characters detected")] public string Name { get; set; }

...but that does not work for globalization/internationalization, i.e. non-latin characters like æ, ø å 汉字.

X-XSS to do >limited< XSS-protection: https://dotnetcoretutorials.com/2017/01/10/set-x-xss-protection-asp-net-core/ Like this but there is only limited support afaik:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.Use(async (context, next) =>
    {
        context.Response.Headers.Add("X-Xss-Protection", "1");
        await next();
    });
 
    app.UseMvc();
}

The documentation from Microsoft is two years old: https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting?view=aspnetcore-2.1 and does not really cover it.

I am thinking to do something simple like:

myField = myField.Replace('<','').Replace('>','').Replace('&','').Repl...;
  • on all data submission - but it seems kind of wonky.

I have asked the same question for Microsoft but I am interested to hear how people are solving this problem in real-life applications.

Update: what we are trying to accomplish:

In our application, we have webforms where people can input names, email, content and similar. The data is stored in a database and will be viewed on a frontend system and possibly other systems in the future (like RSS feeds, JSON, whatever). Some forms contain rich-text editors (TinyMCE) and allow users to markup their texts. Malicious users could enter <script>alert('evil stuff');</script> in the fields. What is the best way to strip the evil characters in ASP.NET Core before it reaches the database - I prefer evil scripts not to be stored in the database at all.

I figured something like this could work:

const string RegExInvalidCharacters = @"[^&<>\""'/]*$";

[RegularExpression(RegExInvalidCharacters, ErrorMessage = "InvalidCharacters")]
public string Name { get; set; }

[RegularExpression(RegExInvalidCharacters, ErrorMessage = "InvalidCharacters")]
public string Content { get; set; }

...
5 Answers

One of the best ways in preventing stored/reflected XSS is to HTML-Encode the output. You may also encode before you store it in the DB. Since you don't need the output from these fields to be in HTML anyways.

The solution with the Regex won't always work. What you're doing here is that you are relying on a blacklist. It's always better and more secure to either rely on Whitelist (Which you don't need in this case). Or HTML-Encode the output if possible.

I know this is a year old now, but for your (and others') reference, you may want to look at creating a ResourceFilter or Middleware which will sanitize incoming requests. You can use whatever tools or custom code you want there, but the key being that all incoming requests go through this filter to be sanitized of bad data.

Be sure to use the correct filter for your application/need. A ResourceFilter will run before model binding, and an ActionFilter will run after model binding.

Specifically, what are you trying to do here? Prevent posts which could contain content which could render, when un-sanitised an XSS attack? If so, as I recently discussed with a colleague, you kind of can't, depending on your site.

You can provide client-side restrictions on the data posted, but this can obviously be bypassed, so what's your action trying to do? Prevent content being posted that when rendered un-sanitised is a potential XSS risk?

What is your post endpoint responsible for? Is it responsible for how other systems may render some output it has received?

I would argue your main XSS risk is in how an app renders your data. If you're not sanitising/encoding output based on the app that is using the data then you're probably doing it wrong.

Remember that a potential XSS issue is only a real issue if you're outputting something to a webpage or similar. This is not really the endpoint that receives the data's problem.

I know this has been answered already, and quite adequately, but I want to add my answer as a way of getting some feedback as well. This is what I have done in this case, which is very similar to the question at hand.

Scenario We have a front-end application built in Vue.js wrapped in "Quasar.dev", which is being served by a .NET 5.0 API on the back side.

Solution We have "public models" which are objects we use to send to the client application. They are not named and formatted as their database fields. We use "AutoMapper" to map from database fields (or models) to public fields (or models) Once the public model has been mapped we then send the public model to the user. Then inside the AutoMapper profile, I added an extension to the String object called .Encode() which encodes whatever comes from the database into the public model field using the following code...

public static string Encoded(this string value)
{
    return HttpUtility.HtmlEncode(value);
}

Now, every time I add new profiles for public models, I just make sure to add that call for encoding on strings I do not trust.

How about that?

Related