Dealing with Common Security Threats in Blazor WebAssembly Hosted App
Dealing with Common Security Threats in Blazor WebAssembly Hosted App
Security is a critical aspect of any web application. In this hands-on exercise, we'll explore how a Blazor WebAssembly Hosted application can be vulnerable to common threats like Cross-Site Scripting (XSS) and SQL Injection, and more importantly, how to fix them using the built-in features of ASP.NET Core and Blazor.
🔐 Lesson 1: Dealing with Common Security Threats in Web Applications
Our goal is to understand how to protect a Blazor WebAssembly Hosted app against XSS and SQL Injection.
🛠 Step 0: Create a New Blazor WebAssembly Hosted App
First, let's create our project using Visual Studio or the command line.
dotnet new blazorwasm -ho -o SecureCommentDemo
This command creates a solution with three projects: a `Client` (Blazor WASM frontend), a `Server` (ASP.NET Core backend), and a `Shared` project for shared models.
✍️ Step 1: Create a Simple Comment Form (Client Side)
Next, we'll create a Razor component that's intentionally vulnerable to XSS.
In the `SecureCommentDemo.Client` project, create a new Razor Component named `CommentPage.razor` in the `Pages` folder and add the following code:
@page "/comment"
@using System.Net.Http.Json
<h3>Post a Comment</h3>
<textarea @bind="commentText" rows="4" cols="50"></textarea><br/>
<button class="btn btn-primary mt-2" @onclick="SubmitComment">Submit</button>
<h4 class="mt-4">Submitted Comment:</h4>
@if (!string.IsNullOrEmpty(submittedComment))
{
@((MarkupString)submittedComment) <!-- Note: this is vulnerable -->
}
@code {
private string commentText = string.Empty;
private string submittedComment = string.Empty;
private void SubmitComment()
{
submittedComment = commentText;
}
}
The key to the vulnerability here is the line `@((MarkupString)submittedComment)`. This explicitly tells Blazor to render the string as raw HTML, bypassing its default automatic HTML encoding.
💣 Step 2: Simulate an XSS Attack
Run the project and navigate to `/comment`. In the text area, paste the following malicious script and click "Submit".
<script>alert('Hacked!')</script>
You will see a pop-up alert box, proving that the malicious JavaScript was executed. This is a classic example of an XSS attack.
🔒 Step 3: Fix the XSS Vulnerability
The fix is to simply remove the `(MarkupString)` cast. Blazor's Razor syntax is designed to be secure by default.
Change this line in `CommentPage.razor`:
@((MarkupString)submittedComment)
To this:
@submittedComment
Now, if you re-run the app and paste the same `script` tag, it will be displayed as literal text on the page, not executed. Blazor automatically encodes the special characters, preventing the XSS attack.
💻 Step 4: Show SQL Injection Risk with a Backend API
While Blazor's client-side is protected, the backend API can still be vulnerable. Let's create a simple, insecure API to demonstrate SQL Injection.
🔧 Backend Setup:
In the `SecureCommentDemo.Server` project, create a new API controller named `CommentController.cs`.
using Microsoft.AspNetCore.Mvc;
using System.Data.SqlClient;
namespace SecureCommentDemo.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CommentController : ControllerBase
{
[HttpPost]
public IActionResult Post([FromBody] string comment)
{
// ❌ DANGEROUS: SQL Injection risk (Example only)
// NEVER use string interpolation like this for database queries
string sql = $"INSERT INTO Comments (Text) VALUES ('{comment}')";
// If a user posts "comment'); DROP TABLE Comments; --", this query becomes:
// INSERT INTO Comments (Text) VALUES ('comment'); DROP TABLE Comments; --')
// The second command will be executed!
// Simulate the response to show it's received
return Ok($"Received comment: {comment}");
}
}
}
Next, update the `SubmitComment` method in `CommentPage.razor` to call this new API. Also, ensure `HttpClient` is registered in `Program.cs` of the Client project.
// In SecureCommentDemo.Client/Program.cs
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// In CommentPage.razor
private async Task SubmitComment()
{
submittedComment = commentText;
await Http.PostAsJsonAsync("api/comment", commentText);
}
The server-side code is a simple example of a **SQL Injection** vulnerability. If an attacker passes a specially crafted string, they could execute arbitrary SQL commands on your database. The solution is to **never** use string interpolation for SQL queries. Always use parameterized queries or a reliable Object-Relational Mapper (ORM) like Entity Framework Core.
📚 Learning Summary
| Concept | What You Learned |
|---|---|
| **XSS** | Cross-Site Scripting can be prevented by avoiding raw HTML rendering. |
| **Razor Encoding** | Blazor's default behavior is to automatically encode user input, making it safe to display. |
| **SQL Injection** | Never use string interpolation for database queries; always use parameterized queries or an ORM. |
| **Secure APIs** | Security is a layered approach. You must validate and sanitize data on the server side as well as the client side. |
Comments
Post a Comment