CSRF vs XSS Attacks
| CSRF | XSS |
|---|---|
| Tricks a logged-in user into sending an unwanted request | Injects malicious JavaScript into a webpage |
| Uses the user’s authentication cookie | Runs code inside the user’s browser |
| Example: Unauthorized money transfer | Example: Stealing cookies or user data |
CSRF protection
ASP.NET Core uses anti-forgery tokens to confirm that a form request came from the application.
<form asp-action="Delete" method="post">
<button type="submit">Delete</button>
</form>
The Form Tag Helper automatically generates the token.
Validate it in the action:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(int id)
{
return RedirectToAction("Index");
}
Additional protection:
options.Cookie.SameSite = SameSiteMode.Lax;
XSS protection
Razor automatically HTML-encodes displayed values:
<p>@Model.Comment</p>
If the comment contains <script>, it is displayed as text instead of being executed.
Additional protections:
- Validate and sanitize user input.
- Avoid
Html.Raw()for untrusted content. - Use a Content Security Policy.
- Mark sensitive cookies as
HttpOnly. - Do not insert untrusted input directly into JavaScript.
Interview answer
CSRF sends an unauthorized request using the user’s existing login cookie. Prevent it using anti-forgery tokens and SameSite cookies.
XSS injects malicious scripts into a page. Prevent it using Razor output encoding, input sanitization and Content Security Policy.
Library: Basic CSRF and Razor encoding protections are built into ASP.NET Core; no additional package is normally required.
What does [ValidateAntiForgeryToken] do?
[ValidateAntiForgeryToken] protects MVC form submissions from CSRF attacks.
It checks whether the request contains a valid anti-forgery token generated by the application.
View
<form asp-action="Delete" method="post">
@Html.AntiForgeryToken()
<button type="submit">Delete</button>
</form>
The Form Tag Helper normally generates the token automatically for POST forms.
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(int id)
{
// Delete record
return RedirectToAction("Index");
}
How it works
ASP.NET Core compares:
- A token stored in a cookie
- A token submitted with the form
If they do not match or are missing, the request is rejected with HTTP 400 Bad Request.
Interview point: It verifies that a state-changing request originated from the application’s own form, helping prevent CSRF attacks.
Library: Built into ASP.NET Core MVC; no additional NuGet package is required.
Apply Anti-Forgery Validation Globally
Register AutoValidateAntiforgeryTokenAttribute as a global MVC filter:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(
new AutoValidateAntiforgeryTokenAttribute());
});
This automatically validates anti-forgery tokens for unsafe HTTP methods:
POSTPUTPATCHDELETE
It does not validate safe methods such as GET, HEAD, OPTIONS, and TRACE.
Exclude a specific action
[IgnoreAntiforgeryToken]
[HttpPost]
public IActionResult ExternalWebhook()
{
return Ok();
}
Use this exclusion carefully—for example, an external webhook that cannot provide your MVC anti-forgery token should use another validation method such as a signature.
Interview point: Global validation avoids adding [ValidateAntiForgeryToken] separately to every state-changing MVC action.
Library: Microsoft.AspNetCore.Mvc.ViewFeatures; included with ASP.NET Core MVC, so no additional NuGet package is normally required.
How do you prevent SQL injection?
SQL injection occurs when untrusted user input is included directly in a SQL command.
Main prevention methods
- Use parameterized queries.
- Use EF Core LINQ queries.
- Never build SQL using string concatenation.
- Validate input, but do not depend on validation alone.
- Use a database account with minimum required permissions.
- Use stored procedures with parameters.
Unsafe code
var sql = "SELECT * FROM Users WHERE Name = '" + name + "'";
Safe parameterized query
var command = new SqlCommand(
"SELECT * FROM Users WHERE Name = @Name", connection);
command.Parameters.AddWithValue("@Name", name);
EF Core
var user = await context.Users
.FirstOrDefaultAsync(x => x.Name == name);
EF Core converts the value into a SQL parameter automatically.
For raw SQL:
var users = await context.Users
.FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {name}")
.ToListAsync();
Interview point: The primary defense is parameterization. It treats user input as data rather than executable SQL.
Libraries: EF Core requires packages such as Microsoft.EntityFrameworkCore.SqlServer. Direct SQL Server access commonly uses Microsoft.Data.SqlClient.
Enforcing HTTPS and HSTS
Configure middleware
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
How they work
UseHttpsRedirection()redirects HTTP requests to HTTPS.UseHsts()sends theStrict-Transport-Securityheader, instructing browsers to use only HTTPS for future requests.
Configure HSTS
builder.Services.AddHsts(options =>
{
options.MaxAge = TimeSpan.FromDays(365);
options.IncludeSubDomains = true;
options.Preload = true;
});
Important points
- Place these middleware components early in the pipeline.
- Do not normally enable HSTS during development.
- Configure a valid TLS/SSL certificate.
- HSTS works only after the browser successfully connects through HTTPS.
- In production, the reverse proxy or load balancer may also handle HTTPS redirection.
Interview answer: HTTPS encrypts data while it travels between client and server. HSTS tells browsers to always use HTTPS, helping prevent protocol-downgrade and cookie-hijacking attacks.
Library: Built into ASP.NET Core; no additional NuGet package is required.