Skip to main content

.NET Cross-Site Scripting

Cross-Site Scripting (XSS) is one of the most common web application security vulnerabilities that can affect .NET applications. In this comprehensive guide, we'll explore what XSS is, how it works in .NET applications, and how to protect your applications against these types of attacks.

What is Cross-Site Scripting (XSS)?

Cross-Site Scripting (XSS) is a security vulnerability that allows attackers to inject malicious client-side scripts into web pages viewed by other users. These attacks occur when an application takes data from a user and sends it to a web browser without properly validating or encoding it.

When successful, XSS attacks enable hackers to:

  • Steal session cookies and impersonate users
  • Capture keystrokes and form data
  • Redirect users to malicious websites
  • Deface websites or manipulate page content
  • Execute arbitrary JavaScript in victims' browsers

Types of XSS Attacks

There are three main types of XSS attacks that can affect .NET applications:

  1. Reflected XSS: Occurs when malicious script is reflected off a web application to the victim's browser through URLs, form submissions, or other immediate responses.

  2. Stored XSS: Happens when malicious script is stored on the target server (like in a database) and later retrieved and displayed to users.

  3. DOM-based XSS: Takes place entirely in the browser when JavaScript manipulates the DOM in an unsafe way.

XSS Vulnerabilities in .NET Applications

.NET applications can be vulnerable to XSS attacks when they:

  • Display user input without proper encoding
  • Render HTML or JavaScript dynamically based on user input
  • Build HTML or URLs with unvalidated user data
  • Use older frameworks that don't have automatic XSS protection

Preventing XSS in .NET Applications

1. Output Encoding

The primary defense against XSS is proper output encoding. ASP.NET provides built-in tools for this:

csharp
// BAD - Direct insertion of user input
@Html.Raw(Model.UserComment) // MVC Razor

// GOOD - Using HTML encoding
@Model.UserComment // MVC Razor (auto-encoded)
@Html.Encode(Model.UserComment) // Classic ASP.NET
HttpUtility.HtmlEncode(userInput) // General purpose

Different contexts require different encoding strategies:

csharp
// HTML context encoding
var encodedHtml = HttpUtility.HtmlEncode(userInput);

// URL encoding
var encodedUrl = HttpUtility.UrlEncode(userInput);

// JavaScript encoding (using AntiXSS library)
var encodedJs = Microsoft.Security.Application.Encoder.JavaScriptEncode(userInput);

2. Content Security Policy (CSP)

Add CSP headers to your .NET application to restrict which scripts can execute:

csharp
// In ASP.NET Core Startup.cs or Program.cs
app.Use(async (context, next) =>
{
context.Response.Headers.Add(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' https://trusted-cdn.com");

await next();
});

3. ASP.NET Core Built-in Protection

ASP.NET Core has built-in XSS protection mechanisms:

csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
// Enforces automatic HTML encoding
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
}

4. Input Validation

Always validate user input before processing it:

csharp
// Backend validation
public class CommentInputModel
{
[Required]
[StringLength(1000)]
[RegularExpression(@"^[^<>]*$", ErrorMessage = "HTML characters are not allowed")]
public string CommentText { get; set; }
}

Real-World Example: Building a Secure Comment System

Let's build a simple but secure comment system in ASP.NET Core:

Step 1: Define the Comment Model

csharp
public class Comment
{
public int Id { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public DateTime PostedDate { get; set; }
}

public class CommentViewModel
{
[Required]
[StringLength(100)]
public string Author { get; set; }

[Required]
[StringLength(2000)]
public string Content { get; set; }
}

Step 2: Create the Controller

csharp
public class CommentsController : Controller
{
private readonly ICommentRepository _commentRepository;

public CommentsController(ICommentRepository commentRepository)
{
_commentRepository = commentRepository;
}

public IActionResult Index()
{
var comments = _commentRepository.GetAllComments();
return View(comments);
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Add(CommentViewModel model)
{
if (!ModelState.IsValid)
{
return RedirectToAction("Index");
}

// Create new comment - content is HTML encoded by default in the view
var comment = new Comment
{
Author = model.Author,
Content = model.Content,
PostedDate = DateTime.Now
};

_commentRepository.AddComment(comment);

return RedirectToAction("Index");
}
}

Step 3: Create the View

cshtml
@model IEnumerable<Comment>

<h2>Comments</h2>

<div class="comment-form">
<form asp-action="Add" asp-controller="Comments" method="post">
@Html.AntiForgeryToken()

<div class="form-group">
<label for="Author">Your Name:</label>
<input type="text" id="Author" name="Author" class="form-control" required maxlength="100" />
</div>

<div class="form-group">
<label for="Content">Comment:</label>
<textarea id="Content" name="Content" class="form-control" required maxlength="2000"></textarea>
</div>

<button type="submit" class="btn btn-primary">Submit Comment</button>
</form>
</div>

<div class="comments-list">
@foreach (var comment in Model)
{
<div class="comment">
<h4>@comment.Author</h4>
<p>@comment.Content</p>
<small>Posted on: @comment.PostedDate.ToString("MMM dd, yyyy")</small>
</div>
}
</div>

Notice that in the Razor view, the @comment.Content automatically HTML encodes the output, protecting against XSS.

Common Vulnerable Patterns to Avoid

1. Using Html.Raw() with User Input

csharp
// VULNERABLE: Bypasses encoding
@Html.Raw(Model.UserGeneratedHtml)

2. Using [AllowHtml] Without Sanitization

csharp
// VULNERABLE: Allows users to submit HTML
[AllowHtml]
public string Description { get; set; }

3. Unsafe JavaScript Data Handling

javascript
// VULNERABLE: Direct insertion of server data into DOM
function showUserInfo() {
// Assuming userInfo comes from the server with user-provided data
document.getElementById('userProfile').innerHTML = userInfo;
}

Using HTML Sanitization Libraries

When you need to allow limited HTML (like for a rich text editor), use a sanitization library:

csharp
// Using HtmlSanitizer package
using HtmlSanitizer;

public class CommentService
{
public string SanitizeUserHtml(string html)
{
var sanitizer = new Sanitizer();

// Configure allowed tags and attributes
sanitizer.AllowedTags.Add("b");
sanitizer.AllowedTags.Add("i");
sanitizer.AllowedTags.Add("p");

return sanitizer.Sanitize(html);
}
}

Usage:

csharp
[HttpPost]
public IActionResult SaveComment(CommentModel model)
{
// Sanitize HTML content before saving
model.Content = _commentService.SanitizeUserHtml(model.Content);

// Now save the sanitized content
_repository.SaveComment(model);

return RedirectToAction("Index");
}

Testing for XSS Vulnerabilities

Simple test payloads to check your application for XSS vulnerabilities:

<script>alert('XSS')</script>
<img src="x" onerror="alert('XSS')">
javascript:alert('XSS')
<div onmouseover="alert('XSS')">Hover over me</div>

Summary

Cross-Site Scripting remains one of the most common security vulnerabilities in web applications, including those built with .NET. By implementing proper output encoding, input validation, and leveraging the built-in protections of modern .NET frameworks, you can significantly reduce the risk of XSS attacks.

Remember these key points:

  • Always encode output when displaying user-provided content
  • Validate and sanitize user input on both client and server sides
  • Use Content Security Policy headers to add an extra layer of protection
  • Consider context-specific encoding for different parts of your HTML
  • Use security libraries for advanced scenarios like HTML sanitization

Additional Resources

  1. OWASP XSS Prevention Cheat Sheet
  2. Microsoft's ASP.NET Core Security Documentation
  3. HtmlSanitizer NuGet Package
  4. AntiXSS Library

Exercise

Exercise 1: Create a simple ASP.NET Core MVC application with a form that accepts user input and displays it back to the user. Implement proper XSS protection using the techniques described in this article.

Exercise 2: Audit an existing .NET application for XSS vulnerabilities. Look for instances where user input is displayed without proper encoding, and fix them using appropriate encoding methods.

Exercise 3: Implement a Content Security Policy in your .NET application and test that it properly restricts unsafe script execution.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)