Skip to content

Commit 80768f7

Browse files
Add Cookie-to-header AntiForgery token validation.
1 parent 5f0b721 commit 80768f7

File tree

4 files changed

+81
-2
lines changed

4 files changed

+81
-2
lines changed

dotnet/src/dotnetcore/GxNetCoreStartup/GxNetCoreStartup.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13+
<PackageReference Include="Microsoft.AspNet.WebPages" Version="3.2.9" />
1314
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="3.1.7" />
1415
<PackageReference Include="Microsoft.AspNetCore.Rewrite" Version="2.2.0" />
1516
<PackageReference Include="Microsoft.Data.SqlClient" Version="1.1.4" />

dotnet/src/dotnetcore/GxNetCoreStartup/Startup.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
2+
13
using System;
24
using System.Collections.Generic;
35
using System.IO;
@@ -12,6 +14,7 @@
1214
using GxClasses.Web.Middleware;
1315
using log4net;
1416
using Microsoft.AspNetCore;
17+
using Microsoft.AspNetCore.Antiforgery;
1518
using Microsoft.AspNetCore.Builder;
1619
using Microsoft.AspNetCore.DataProtection;
1720
using Microsoft.AspNetCore.Diagnostics;
@@ -104,6 +107,10 @@ private static void LocatePhysicalLocalPath()
104107

105108
public static class GXHandlerExtensions
106109
{
110+
public static IApplicationBuilder UseAntiforgeryTokens(this IApplicationBuilder app, string basePath)
111+
{
112+
return app.UseMiddleware<ValidateAntiForgeryTokenMiddleware>(basePath);
113+
}
107114
public static IApplicationBuilder UseGXHandlerFactory(this IApplicationBuilder builder, string basePath)
108115
{
109116
return builder.UseMiddleware<HandlerFactory>(basePath);
@@ -223,6 +230,13 @@ public void ConfigureServices(IServiceCollection services)
223230
options.EnableForHttps = true;
224231
});
225232
}
233+
if (RestAPIHelpers.ValidateCsrfToken())
234+
{
235+
services.AddAntiforgery(options =>
236+
{
237+
options.HeaderName = HttpHeader.X_GXCSRF_TOKEN;
238+
});
239+
}
226240
DefineCorsPolicy(services);
227241
services.AddMvc();
228242
}
@@ -386,6 +400,24 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos
386400

387401
string restBasePath = string.IsNullOrEmpty(VirtualPath) ? REST_BASE_URL : $"{VirtualPath}/{REST_BASE_URL}";
388402
string apiBasePath = string.IsNullOrEmpty(VirtualPath) ? string.Empty : $"{VirtualPath}/";
403+
if (RestAPIHelpers.ValidateCsrfToken())
404+
{
405+
406+
var antiforgery = app.ApplicationServices.GetRequiredService<IAntiforgery>();
407+
app.UseAntiforgeryTokens(restBasePath);
408+
app.Run(async context =>
409+
{
410+
string requestPath = context.Request.Path.Value;
411+
412+
if (string.Equals(requestPath, $"/{restBasePath}VerificationToken", StringComparison.OrdinalIgnoreCase))
413+
{
414+
var tokenSet = antiforgery.GetAndStoreTokens(context);
415+
context.Response.Cookies.Append(HttpHeader.X_GXCSRF_TOKEN, tokenSet.RequestToken!,
416+
new CookieOptions { HttpOnly = false });
417+
}
418+
await Task.CompletedTask;
419+
});
420+
}
389421
app.UseMvc(routes =>
390422
{
391423
foreach (string serviceBasePath in servicesBase)
@@ -485,6 +517,13 @@ public async Task Invoke(HttpContext httpContext)
485517
{
486518
httpStatusCode = HttpStatusCode.NotFound;
487519
}
520+
521+
else if (ex is AntiforgeryValidationException)
522+
{
523+
//"The required antiforgery header value "X-GXCSRF-TOKEN" is not present.
524+
httpStatusCode = HttpStatusCode.BadRequest;
525+
GXLogging.Error(log, $"Validation of antiforgery failed", ex);
526+
}
488527
else
489528
{
490529
httpStatusCode = HttpStatusCode.InternalServerError;
@@ -542,4 +581,43 @@ public IActionResult Index()
542581
return Redirect(defaultFiles[0]);
543582
}
544583
}
584+
public class ValidateAntiForgeryTokenMiddleware
585+
{
586+
static readonly ILog log = log4net.LogManager.GetLogger(typeof(ValidateAntiForgeryTokenMiddleware));
587+
588+
private readonly RequestDelegate _next;
589+
private readonly IAntiforgery _antiforgery;
590+
private string _basePath;
591+
592+
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery, String basePath)
593+
{
594+
_next = next;
595+
_antiforgery = antiforgery;
596+
_basePath = "/" + basePath;
597+
}
598+
599+
public async Task Invoke(HttpContext context)
600+
{
601+
if (context.Request.Path.HasValue && context.Request.Path.Value.StartsWith(_basePath) && HttpMethods.IsPost(context.Request.Method))
602+
{
603+
GXLogging.Debug(log, $"Antiforgery validation starts");
604+
await _antiforgery.ValidateRequestAsync(context);
605+
GXLogging.Debug(log, $"Antiforgery validation OK");
606+
}
607+
else if (HttpMethods.IsGet(context.Request.Method))
608+
{
609+
string tokens = context.Request.Cookies[HttpHeader.X_GXCSRF_TOKEN];
610+
if (string.IsNullOrEmpty(tokens))
611+
{
612+
GXLogging.Debug(log, $"Setting cookie ", HttpHeader.X_GXCSRF_TOKEN);
613+
var tokenSet = _antiforgery.GetAndStoreTokens(context);
614+
context.Response.Cookies.Append(HttpHeader.X_GXCSRF_TOKEN, tokenSet.RequestToken!,
615+
new CookieOptions { HttpOnly = false });
616+
}
617+
}
618+
619+
await _next(context);
620+
}
621+
622+
}
545623
}

dotnet/src/dotnetframework/GxClasses/Services/GXRestServices.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ private bool IsAuthenticated(GAMSecurityLevel objIntegratedSecurityLevel, bool o
451451
{
452452

453453
string CSRFToken;
454-
bool validateCSRFToken = RestAPIHelpers.ValidateCsrfToken(); ;
454+
bool validateCSRFToken = false;//RestAPIHelpers.ValidateCsrfToken(); ;
455455
if (objIntegratedSecurityLevel == GAMSecurityLevel.SecurityLow)
456456
{
457457
bool isOK;

dotnet/src/dotnetframework/GxClasses/Services/GxRestWrapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ protected bool IsAuthenticated(GAMSecurityLevel objIntegratedSecurityLevel, bool
568568
else
569569
{
570570
string CSRFToken;
571-
bool validateCSRFToken = RestAPIHelpers.ValidateCsrfToken();
571+
bool validateCSRFToken = false;// RestAPIHelpers.ValidateCsrfToken();
572572
if (objIntegratedSecurityLevel == GAMSecurityLevel.SecurityLow)
573573
{
574574
bool isOK;

0 commit comments

Comments
 (0)