'Getting a SameSite cookie issue when trying to load recaptcha api.js in ASP.Net core project
I am trying to add a Google v2 reCaptcha on my ASP.Net Core 6 Web Application and test it on my localhost. When I add the following line:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
to my page and open the page I am getting the following error in Chrome's console:
Because a cookie’s SameSite attribute was not set or is invalid, it defaults to SameSite=Lax, which prevents the cookie from being sent in a cross-site request. This behavior protects user data from accidentally leaking to third parties and cross-site request forgery. Resolve this issue by updating the attributes of the cookie: Specify SameSite=None and Secure if the cookie should be sent in cross-site requests. This enables third-party use. Specify SameSite=Strict or SameSite=Lax if the cookie should not be sent in cross-site requests.
All the cookies and request given after are from google.com.
The Captcha is not working and it also prevents some other JS scripts from execution.
If I remove the above line the page loads normally.
Here is how my Program.cs file looks like:
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Serilog;
using Serilog.Events;
using XQ.XGoogleInvisibleCaptcha;
[assembly: System.Runtime.InteropServices.ComVisible(true)]
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.File(
"logs\\Logs.txt",
rollingInterval: RollingInterval.Day,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}\n")
.WriteTo.Console(
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}\n")
.CreateLogger();
var lBuilder = WebApplication.CreateBuilder(args);
lBuilder.Host.UseSerilog();
// Build configuration
string lBasePath = Directory.GetParent(AppContext.BaseDirectory) == null ? string.Empty : Directory.GetParent(AppContext.BaseDirectory).FullName;
var lConfiguration = new ConfigurationBuilder()
.SetBasePath(lBasePath)
.AddJsonFile("appsettings.json", false)
.Build();
// Add caching of the static files
lBuilder.Services.AddResponseCaching();
// Add cookies
var cookieOptions = new CookieOptions
{
// Set the secure flag, which Chrome's changes will require for SameSite none.
// Note this will also require you to be running on HTTPS.
Secure = true,
// Set the cookie to HTTP only which is good practice unless you really do need
// to access it client side in scripts.
HttpOnly = true,
// Add the SameSite attribute, this will emit the attribute with a value of none.
// To not emit the attribute at all set
// SameSite = (SameSiteMode)(-1)
SameSite = SameSiteMode.None,
};
// Use memory cache for the session
lBuilder.Services.AddDistributedMemoryCache();
// Add session to store data
lBuilder.Services.AddSession(options =>
{
options.Cookie.Name = ".MyWeb.Session";
options.IdleTimeout = TimeSpan.FromMinutes(2.0);
});
lBuilder.Services.AddCors();
// Add services to the container.
lBuilder.Services.AddSingleton<IConfigurationRoot>(lConfiguration);
// Add the configuration of the Google Invisible Captcha
XGoogleInvisibleCaptchaKeys lGoogleInvisibleCaptchaKeys = lBuilder.Environment.IsDevelopment() ?
lConfiguration.GetSection("GoogleInvisibleCaptchaDev").Get<XGoogleInvisibleCaptchaKeys>() :
new(); //
lBuilder.Services.AddSingleton<ICaptchaKeys>(lGoogleInvisibleCaptchaKeys);
// Add the service for obtaining user IP and cookies
lBuilder.Services.AddHttpContextAccessor();
lBuilder.Services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
// Add services to the container.
lBuilder.Services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute(
"/Account/Signup", "Signup");
});
var lApp = lBuilder.Build();
// Configure the HTTP request pipeline.
if (!lApp.Environment.IsDevelopment())
{
lApp.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
lApp.UseHsts();
}
else
{
lApp.UseDeveloperExceptionPage();
}
lApp.UseHttpsRedirection();
lApp.UseStaticFiles();
lApp.UseRouting();
lApp.UseResponseCaching();
// Global CORS policy
lApp.UseCors(x => x
.SetIsOriginAllowed(origin => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
// Global Headers
lApp.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Developed-By", "Xequtor");
context.Response.Headers.Add("Cache-Control", "no-store");
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("Content-Security-Policy", "form-action 'self'");
// Cache control
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue
{
Public = true,
MaxAge = TimeSpan.FromDays(365),
};
context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] =
new[] { "Accept-Encoding" };
context.Response.Cookies.Append("MyCookies", "cookieValue", cookieOptions);
await next();
});
// Redirect to this page when a server error occurs
lApp.UseStatusCodePagesWithReExecute("/Error");
lApp.UseSession();
lApp.UseAuthorization();
lApp.MapRazorPages();
lApp.Run();
From all the post I have seen so far I understood it has to do something on the Google side but might as well be something I am missing. Any ideas?
Thanks.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|