Dealing with Common Security Threats in Blazor WebAssembly Hosted App

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.

Raushan Ranjan

Microsoft Certified Trainer

.NET | Azure | Power Platform | WPF | Qt/QML Developer

Power BI Developer | Data Analyst

📞 +91 82858 62455
🌐 raushanranjan.azurewebsites.net
🔗 linkedin.com/in/raushanranjan

Comments

Popular posts from this blog

Blazor: Building Web Apps with C# - Introduction

Blazor WebAssembly Hosted App Tutorial: Envelope Tracker System

Securing MVC-based Applications Using Blazor