Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate antiforgery tokens with IAntiforgery #1133

Merged
merged 1 commit into from
May 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions VocaDbWeb/Models/Shared/GlobalValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public MenuPageLink(MenuPage.Link model)
public MenuPageLink[] SmallBanners { get; init; }
public MenuPageLink[] SocialLinks { get; init; }

public string? RequestToken { get; init; }

public GlobalValues(VocaDbPage model)
{
AlbumTypes = AppConfig.AlbumTypes;
Expand Down
2 changes: 2 additions & 0 deletions VocaDbWeb/Scripts/Shared/GlobalValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ export default interface GlobalValues {
bigBanners: MenuPageLink[];
smallBanners: MenuPageLink[];
socialLinks: MenuPageLink[];

requestToken?: string;
}
16 changes: 16 additions & 0 deletions VocaDbWeb/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using AspNetCore.CacheOutput.Extensions;
using AspNetCore.CacheOutput.InMemory.Extensions;
using Autofac;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Twitter;
using Microsoft.AspNetCore.Mvc.Formatters;
Expand Down Expand Up @@ -292,6 +293,21 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseAuthentication();
app.UseAuthorization();

// Code from: https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-6.0#generate-antiforgery-tokens-with-iantiforgery.
var antiforgery = app.ApplicationServices.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;

if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase) || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!, new CookieOptions { HttpOnly = false });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sets a cookie named XSRF-TOKEN. The client can read this cookie and provide its value as a header attached to AJAX requests. See Generate antiforgery tokens with IAntiforgery.

}

return next(context);
});

app.UseVocaDbPrincipal();

app.UseResponseCaching();
Expand Down
12 changes: 11 additions & 1 deletion VocaDbWeb/Views/Shared/React/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@using VocaDb.Web.Models.Shared.Partials.Html
@inherits VocaDbPage
@addTagHelper *, VocaDb.ReMikus
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery

@{
Layout = null;
Expand Down Expand Up @@ -56,7 +57,16 @@
</head>
<body class="vdb">
<div id="app"></div>
<script>window.vdb = @ToJS(new { Resources = new GlobalResources(this), Values = new GlobalValues(this) })</script>
<script>
window.vdb = @ToJS(new
{
Resources = new GlobalResources(this),
Values = new GlobalValues(this)
{
RequestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React/Index.cshtml is the single page that will host the React app. The same token will be used multiple times, unless a full page refresh is triggered. See also javascript - Single Page Application and CSRF Token - Stack Overflow.

},
});
</script>
<remikus path="/bundles/manifest.js" />
<remikus path="/bundles/vendor.js" />
<remikus path="/bundles/index.js" />
Expand Down