/// <summary> /// Add Strict-Transport-Security max-age=0 to all requests. /// Tells the user-agent to remove, or not cache the host in the STS cache /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddStrictTransportSecurityNoCache(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new StrictTransportSecurityHeader($"max-age=0"))); }
/// <summary> /// Add a Cross-Origin-Opener-Policy Header Report-Only to all requests /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="configure">Configure the COOP</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddCrossOriginOpenerPolicyReportOnly(this HeaderPolicyCollection policies, Action <CrossOriginOpenerPolicyBuilder> configure) { return(policies.ApplyPolicy(CrossOriginOpenerPolicyHeader.Build(configure, asReportOnly: true))); }
/// <summary> /// Add a Content-Security-Header-Report-Only to all requests /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="configure">Configure the CSP</param> public static HeaderPolicyCollection AddContentSecurityPolicyReportOnly(this HeaderPolicyCollection policies, Action <CspBuilder> configure) { return(policies.ApplyPolicy(ContentSecurityPolicyHeader.Build(configure, asReportOnly: true))); }
/// <summary> /// Add X-XSS-Protection 0 to all requests. /// Disables the XSS Protections offered by the user-agent. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddXssProtectionDisabled(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(XssProtectionHeader.Disabled())); }
/// <summary> /// Add X-XSS-Protection 1; report=http://site.com/report to all requests. /// A partially supported directive that tells the user-agent to report potential XSS attacks to a single URL. Data will be POST'd to the report URL in JSON format. /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="reportUrl">The url to report potential XSS attacks to</param> public static HeaderPolicyCollection AddXssProtectionReport(this HeaderPolicyCollection policies, string reportUrl) { return(policies.ApplyPolicy(XssProtectionHeader.Block())); }
/// <summary> /// Add a Cross-Origin-Resource-Policy Header to all requests /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="configure">Configure the CORP</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddCrossOriginResourcePolicy(this HeaderPolicyCollection policies, Action <CrossOriginResourcePolicyBuilder> configure) { return(policies.ApplyPolicy(CrossOriginResourcePolicyHeader.Build(configure))); }
/// <summary> /// Remove a custom header from all requests /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="header">The header value to remove</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection RemoveCustomHeader(this HeaderPolicyCollection policies, string header) { return(policies.ApplyPolicy(new RemoveCustomHeader(header))); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure( IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { // 追蹤阻塞調用 app.UseBlockingDetection(); app.UseDeveloperExceptionPage(); } if (Configuration.GetValue <bool>("MiniProfiler:Enable")) { app.UseMiniProfiler(); } // 轉發標頭 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All }); #region Firewall /* * app.UseFirewall( * FirewallRulesEngine * .DenyAllAccess() * .ExceptFromIPAddressRanges(allowedCIDRs) * .ExceptFromIPAddresses(allowedIPs)); */ #endregion // 回應緩衝 app.UseResponseBuffering(); app.UseRouting(); #region Security Headers var policyCollection = new HeaderPolicyCollection() .AddFrameOptionsDeny() .AddXssProtectionBlock() .AddContentTypeOptionsNoSniff() .AddReferrerPolicyStrictOriginWhenCrossOrigin() .RemoveServerHeader(); //.AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365) //.AddContentSecurityPolicy(builder => { // builder.AddObjectSrc().None(); // builder.AddFormAction().Self(); // builder.AddFrameAncestors().None(); //}); app.UseSecurityHeaders(policyCollection); #endregion // Hangfire UI if (Configuration.GetValue <bool>("Hangfire:Enable")) { // 加入Hangfire伺服器 app.UseHangfireServer(); // 加入Hangfire控制面板 app.UseHangfireDashboard( pathMatch: Configuration.GetValue <string>("Hangfire:PathMatch"), options: new DashboardOptions() // 使用自訂的認證過濾器 { Authorization = new[] { new HangfireAuthorizeFilter() } } ); } // Swagger UI if (Configuration.GetValue <bool>("Swagger:Enable")) { app.UseOpenApiAndSwaggerUi3(); } // 使用認證 app.UseAuthentication(); // 使用MVC app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); // 使用靜態檔案 app.UseStaticFiles(); // 使用SPA app.UseSpa(); }
/// <summary> /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. /// </summary> /// <param name="app">The application to configure.</param> /// <param name="env">The environment information to use in configuration phase.</param> /// <param name="applicationLifetime"></param> public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime) { app.UseProblemDetails(); if (!env.IsProduction()) { //This test middleware needs to be before developer exception pages. app.Use(TestMiddleware); app.UseDeveloperExceptionPage(); } //app.UseHealthChecks("/healthz"); //app.UseMiddleware<StartupTasksMiddleware>(); applicationLifetime.ApplicationStopping.Register(() => { }); //This ensures (or improves chances) to flush log buffers before (a graceful) shutdown. //It appears there isn't other way (e.g. in Program) than taking a reference to the global //static Serilog instance. applicationLifetime.ApplicationStopped.Register(Log.CloseAndFlush); //Security headers will always be added and by default the disallow everything. //The trimming is a robustness measure to make sure the URL has one trailing slash. //The listening address is needed for security headers. This is the public //API address. var appsettingsSection = Configuration.GetSection("AppSettings"); var listeningAddress = appsettingsSection["OneBoxDeploymentApiUrl"]; listeningAddress = (listeningAddress ?? app.ServerFeatures.Get <IServerAddressesFeature>().Addresses.FirstOrDefault()).EnsureTrailing('/'); //Note: the constructor checks ConfigurationKeys forbidden in production are not found. if (!env.IsProduction()) { //Creates a route to specifically throw and unhandled exception. This route is most likely injected only in testing. //This kind of testing middleware can be made to one code block guarded appropriately if there is more of it. var alwaysFaultyRoute = Configuration.GetValue <string>(ConfigurationKeys.AlwaysFaultyRoute, null); if (alwaysFaultyRoute != null) { app.Use((context, next) => { if (context.Request.Path.StartsWithSegments($"/{alwaysFaultyRoute}", out _, out _)) { throw new Exception($"Fault injected route for testing ({context.Request.PathBase}/{alwaysFaultyRoute})."); } return(next()); }); } } Logger.LogInformation(Events.SwaggerDocumentation.Id, Events.SwaggerDocumentation.FormatString, listeningAddress + SwaggerRoot + "/"); var defaultSecurityPolicies = new HeaderPolicyCollection() .AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365) .RemoveServerHeader() .AddFrameOptionsDeny(); app.UseSecurityHeaders(defaultSecurityPolicies); app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments("/" + SwaggerRoot), swaggerBranch => { //See configuration at https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders. const string GoogleStyles = "https://fonts.googleapis.com"; const string GoogleFontsUrl = "https://fonts.gstatic.com"; var clientUrl = Path.Combine(listeningAddress, SwaggerRoot).EnsureTrailing('/'); //Additional information for the many Feature-Policy none definitions: //https://github.com/w3c/webappsec-feature-policy/issues/189#issuecomment-452401661. swaggerBranch.UseSecurityHeaders(new HeaderPolicyCollection().AddFeaturePolicy(builder => { builder.AddAccelerometer().None(); builder.AddAmbientLightSensor().None(); builder.AddAutoplay().None(); builder.AddCamera().None(); builder.AddEncryptedMedia().None(); builder.AddFullscreen().None(); builder.AddGeolocation().None(); builder.AddGyroscope().None(); builder.AddMagnetometer().None(); builder.AddMicrophone().None(); builder.AddMidi().None(); builder.AddPayment().None(); builder.AddPictureInPicture().None(); builder.AddSpeaker().None(); builder.AddSyncXHR().None(); builder.AddUsb().None(); builder.AddVR().None(); }) .AddXssProtectionBlock() .AddContentTypeOptionsNoSniff() .AddReferrerPolicyStrictOriginWhenCrossOrigin() .AddContentSecurityPolicy(builder => { builder.AddReportUri().To("/cspreport"); builder.AddBlockAllMixedContent(); builder.AddConnectSrc().Self(); builder.AddStyleSrc().Self().UnsafeInline().Sources.Add(GoogleStyles); builder.AddFontSrc().Self().Sources.Add(GoogleFontsUrl); builder.AddImgSrc().Self().Sources.Add("data:"); builder.AddScriptSrc().Self().UnsafeInline(); builder.AddObjectSrc().None(); builder.AddFormAction().Self(); builder.AddFrameAncestors().None().Sources.Add(clientUrl); }, asReportOnly: false)); }); //For further Swagger related information, see at //https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger. app.UseSwagger(); app.UseSwagger(swagger => swagger.RouteTemplate = $"{SwaggerRoot}/{{documentName}}/swagger.json"); if (Configuration["HideSwaggerUi"]?.Equals("true") != true) { app.UseSwaggerUI(swaggerSetup => { swaggerSetup.SwaggerEndpoint($"/{SwaggerRoot}/{SwaggerDocumentationBasePath}/swagger.json", SwaggerDocumentationBasePath); swaggerSetup.RoutePrefix = SwaggerRoot; swaggerSetup.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream($"{Assembly.GetAssembly(typeof(Startup)).GetName().Name}.wwwroot.swagger.index.html"); }); } app.UseCors("CorsPolicy"); app.UseStaticFiles(); app.UseRouting(); //app.UseAuthorization(); app.UseEndpoints(endpoints => endpoints.MapControllers()); }
/// <summary> /// The browser will send the full URL to requests to the same origin but /// only send the origin when requests are cross-origin, as long as a scheme /// downgrade has not happened (i.e. you are not moving from HTTPS to HTTP) /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddReferrerPolicyStrictOriginWhenCrossOrigin(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new ReferrerPolicyHeader("strict-origin-when-cross-origin"))); }
/// <summary> /// The browser will always send the full URL with any request to any origin. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddReferrerPolicyUnsafeUrl(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new ReferrerPolicyHeader("unsafe-url"))); }
/// <summary> /// The browser will always set the referrer header to the origin from which the request was made. /// This will strip any path information from the referrer information. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddReferrerPolicyOrigin(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new ReferrerPolicyHeader("origin"))); }
/// <summary> /// The browser will not send the referrer header when navigating from HTTPS to HTTP, /// but will always send the full URL in the referrer header when navigating /// from HTTP to any origin. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddReferrerPolicyNoReferrerWhenDowngrade(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new ReferrerPolicyHeader("no-referrer-when-downgrade"))); }
/// <summary> /// Instructs the browser to never send the referrer header with requests /// that are made from your site. This also include links to pages on your own site. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddReferrerPolicyNoReferrer(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new ReferrerPolicyHeader("no-referrer"))); }
public void AddCustomHeader_WhenNullValue_DoesntThrow() { var collection = new HeaderPolicyCollection(); collection.AddCustomHeader("header", "value"); }
public static HeaderPolicyCollection GetHeaderPolicyCollection(bool isDev, string idpHost) { var policy = new HeaderPolicyCollection() .AddFrameOptionsDeny() .AddXssProtectionBlock() .AddContentTypeOptionsNoSniff() .AddReferrerPolicyStrictOriginWhenCrossOrigin() .AddCrossOriginOpenerPolicy(builder => { builder.SameOrigin(); }) .AddCrossOriginResourcePolicy(builder => { builder.SameOrigin(); }) .AddCrossOriginEmbedderPolicy(builder => // remove for dev if using hot reload { builder.RequireCorp(); }) .AddContentSecurityPolicy(builder => { builder.AddObjectSrc().None(); builder.AddBlockAllMixedContent(); builder.AddImgSrc().Self().From("data:"); builder.AddFormAction().Self().From(idpHost); builder.AddFontSrc().Self(); builder.AddStyleSrc().Self(); builder.AddBaseUri().Self(); builder.AddFrameAncestors().None(); // due to Blazor builder.AddScriptSrc() .Self() .WithHash256("v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA=") .UnsafeEval(); // disable script and style CSP protection if using Blazor hot reload // if using hot reload, DO NOT deploy with an insecure CSP }) .RemoveServerHeader() .AddPermissionsPolicy(builder => { builder.AddAccelerometer().None(); builder.AddAutoplay().None(); builder.AddCamera().None(); builder.AddEncryptedMedia().None(); builder.AddFullscreen().All(); builder.AddGeolocation().None(); builder.AddGyroscope().None(); builder.AddMagnetometer().None(); builder.AddMicrophone().None(); builder.AddMidi().None(); builder.AddPayment().None(); builder.AddPictureInPicture().None(); builder.AddSyncXHR().None(); builder.AddUsb().None(); }); if (!isDev) { // maxage = one year in seconds policy.AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365); } return(policy); }
/// <summary> /// Removes the Server header from all responses /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection RemoveServerHeader(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(ServerHeader.Remove())); }
/// <summary> /// Initializes a new instance of the <see cref="SecurityHeadersMiddleware"/> class. /// </summary> /// <param name="next">The next middleware in the pipeline.</param> /// <param name="service">An instance of <see cref="ICustomHeaderService"/>.</param> /// <param name="policies">A <see cref="HeaderPolicyCollection"/> containing the policies to be applied.</param> public SecurityHeadersMiddleware(RequestDelegate next, ICustomHeaderService service, HeaderPolicyCollection policies) : this(next, service, policies, new NonceGenerator()) { _mustGenerateNonce = MustGenerateNonce(_policy); }
/// <summary> /// Add a Permissions-Policy header to all requests /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="configure">Configure the Permissions-Policy</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddPermissionsPolicy(this HeaderPolicyCollection policies, Action <PermissionsPolicyBuilder> configure) { return(policies.ApplyPolicy(PermissionsPolicyHeader.Build(configure))); }
/// <summary> /// Initializes a new instance of the <see cref="SecurityHeadersMiddleware"/> class. /// </summary> /// <param name="next">The next middleware in the pipeline.</param> /// <param name="service">An instance of <see cref="ICustomHeaderService"/>.</param> /// <param name="policies">A <see cref="HeaderPolicyCollection"/> containing the policies to be applied.</param> /// <param name="nonceGenerator">Used to generate nonce (number used once) values for headers</param> internal SecurityHeadersMiddleware(RequestDelegate next, ICustomHeaderService service, HeaderPolicyCollection policies, NonceGenerator nonceGenerator) { _next = next ?? throw new ArgumentNullException(nameof(next)); CustomHeaderService = service ?? throw new ArgumentNullException(nameof(service)); _policy = policies ?? throw new ArgumentNullException(nameof(policies)); _nonceGenerator = nonceGenerator ?? throw new ArgumentException(nameof(nonceGenerator)); }
public static IApplicationBuilder UseStatCanSecurityHeaders(this IApplicationBuilder app) { var env = app.ApplicationServices.GetRequiredService <IHostEnvironment>(); var policyCollection = new HeaderPolicyCollection() .AddFrameOptionsSameOrigin() .AddXssProtectionEnabled() .AddContentTypeOptionsNoSniff() .AddReferrerPolicyStrictOriginWhenCrossOrigin() .RemoveServerHeader() .AddContentSecurityPolicy(builder => { builder.AddObjectSrc().Self(); // Domains here for OAuth redirects builder.AddFormAction().Self().From("github.com").From("account.gccollab.ca").From("login.microsoftonline.com"); builder.AddFrameAncestors().Self(); builder.AddDefaultSrc().Self(); builder.AddImgSrc().Self().Data().From("*.statcan.ca").From("*.statcan.gc.ca") .From("*.omtrdc.net").From("*.demdex.net").From("cm.everesttech.net"); // adobe analytics builder.AddFontSrc().Self().Data().From("cdn.jsdelivr.net").From("fonts.googleapis.com").From("fonts.gstatic.com").From("cdn.materialdesignicons.com"); builder.AddStyleSrc().UnsafeInline().Self() .From("cdn.materialdesignicons.com") .From("cdn.jsdelivr.net") .From("fonts.googleapis.com") .From("code.jquery.com") .From("unpkg.com") .From("cdnjs.cloudflare.com") .From("stackpath.bootstrapcdn.com"); builder.AddConnectSrc().Self().From("*.statcan.ca").From("*.statcan.gc.ca").From("cdn.jsdelivr.net").From("dpm.demdex.net").From("canada.sc.omtrdc.net"); // adobe analytics builder.AddScriptSrc() .UnsafeEval() // for vue-js in oc admin .UnsafeInline() // for oc admin .Self() .From("https://www.google.com/recaptcha/").From("https://www.gstatic.com/recaptcha/") //recaptcha .From("cdn.jsdelivr.net") .From("code.jquery.com") .From("ajax.googleapis.com") .From("cdnjs.cloudflare.com") .From("vuejs.org") .From("unpkg.com") .From("stackpath.bootstrapcdn.com") .From("*.statcan.ca") .From("*.statcan.gc.ca") .From("*.2o7.net") // adobe analytics .From("*.omtrdc.net") // adobe analytics .From("*.tt.omtrdc.net") // adobe analytics .From("assets.adobedtm.com") // adobe analytics .From("*.demdex.net") // adobe analytics .From("cm.everesttech.net") // adobe analytics .From("*.adobe.com"); // adobe analytics builder.AddFrameSrc().Self() .From("canada.demdex.net") // adobe analytics .From("https://www.google.com/recaptcha/"); }); if (!env.IsDevelopment()) { policyCollection.AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365); // maxage = one year in seconds } return(app.UseSecurityHeaders(policyCollection)); }
public static IApplicationBuilder UseCustomHeadersMiddleware(this IApplicationBuilder app, HeaderPolicyCollection policies) { if (app == null) { throw new ArgumentNullException(nameof(app)); } if (policies == null) { throw new ArgumentNullException(nameof(policies)); } return(app.UseMiddleware <CustomHeadersMiddleware>(policies)); }
/// <summary> /// Add X-XSS-Protection 1; mode=block to all requests. /// Enables XSS protections and instructs the user-agent to block the response in the event that script has been inserted from user input, instead of sanitizing. /// </summary> /// <param name="policies">The collection of policies</param> public static HeaderPolicyCollection AddXssProtectionBlock(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(XssProtectionHeader.Block())); }
/// <summary> /// Add X-XSS-Protection 1 to all requests. /// Enables the XSS Protections /// </summary> /// <param name="policies">The collection of policies</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddXssProtectionEnabled(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new XssProtectionHeader("1"))); }
/// <summary> /// Add X-Content-Type-Options nosniff to all requests. /// Disables content sniffing /// Can be set to protect against MIME type confusion attacks. /// </summary> /// <param name="policies">The collection of policies</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddContentTypeOptionsNoSniff(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new XContentTypeOptionsHeader("nosniff"))); }
/// <summary> /// Add X-XSS-Protection 1; mode=block to all requests. /// Enables XSS protections and instructs the user-agent to block the response in the event that script has been inserted from user input, instead of sanitizing. /// </summary> /// <param name="policies">The collection of policies</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddXssProtectionBlock(this HeaderPolicyCollection policies) { return(policies.ApplyPolicy(new XssProtectionHeader("1; mode=block"))); }
/// <summary> /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. /// </summary> /// <param name="app">The application.</param> /// <param name="env">The env.</param> /// <param name="antiforgery">The antiforgery.</param> /// <param name="loggerFactory">The logger factory.</param> /// <param name="serviceProvider">The service provider.</param> /// <param name="seeder">The database seeder.</param> public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, DataSeeder seeder) { HttpContextAccessor = app.ApplicationServices.GetRequiredService <IHttpContextAccessor>(); _userService = serviceProvider.GetService <IUserAccountService>(); _authService = serviceProvider.GetService <IAuthService>(); _crypto = serviceProvider.GetService <ICrypto>(); app.UseCors("CorsPolicy"); app.UseTokenProvider(_tokenOptions, _signingKey); var localizationOptions = app.ApplicationServices.GetService <IOptions <RequestLocalizationOptions> >(); localizationOptions.Value.RequestCultureProviders.Insert(0, new UrlRequestCultureProvider()); app.UseRequestLocalization(localizationOptions.Value); // Show Index.html as default page app.UseDefaultFiles(); app.UseStaticFiles(); //app.UseHangfireDashboard(); //app.UseHangfireServer(); //const int maxAge = 60*60*24*365; var policyCollection = new HeaderPolicyCollection() .AddFrameOptionsDeny() .AddXssProtectionBlock() .AddContentTypeOptionsNoSniff() .AddStrictTransportSecurityMaxAge() // maxage = one year in seconds .RemoveServerHeader(); //.AddCustomHeader("X-TOTAL-RECORDS", "Header value"); app.UseCustomHeadersMiddleware(policyCollection); //RecurringJob.AddOrUpdate(() => Console.WriteLine("Minutely Job"), Cron.Minutely); app.UseWebSockets(); app.UseSignalR <RawConnection>("/signalr"); app.UseMiddleware(typeof(ErrorHandlingMiddleware)); // Add MVC to the request pipeline. app.UseMvc(routes => { var cultureConstraint = new { Culture = new RegexRouteConstraint("^[a-z]{{2}}-[A-Z]{{2}}$") }; routes.MapRoute( "apiVersionCulture", "api/{version}/{culture}/{controller}/{action=Index}/{id?}", cultureConstraint ); routes.MapRoute( "apiVersion", "api/{version}/{controller}/{action=Index}/{id?}" ); routes.MapRoute( "apiCulture", "api/{culture}/{controller}/{action=Index}/{id?}", cultureConstraint ); routes.MapRoute( "default", "{controller=Home}/{action=Index}/{id?}" ); }); // https://github.com/domaindrivendev/Swashbuckle.AspNetCore // Middleware to expose the generated Swagger as JSON endpoint(s) app.UseSwagger(); // Middleware to expose interactive documentation app.UseSwaggerUI(c => { c.ShowJsonEditor(); c.SwaggerEndpoint("/swagger/v1/swagger.json", AppSettings.Information.Name); c.DocExpansion("full"); c.ShowRequestHeaders(); c.SupportedSubmitMethods(new[] { "get", "post", "delete", "put", "patch" }); c.InjectOnCompleteJavaScript("/swagger-ui/on-complete.js"); c.InjectOnFailureJavaScript("/swagger-ui/on-failure.js"); }); app.Use(next => context => { if (!string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase) && !string.Equals(context.Request.Path.Value, "/index.html", StringComparison.OrdinalIgnoreCase)) { return(next(context)); } var tokens = antiforgery.GetAndStoreTokens(context); context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false }); return(next(context)); }); seeder.SeedAsync().Wait(); }
/// <summary> /// Add X-XSS-Protection 1; report=http://site.com/report to all requests. /// A partially supported directive that tells the user-agent to report potential XSS attacks to a single URL. Data will be POST'd to the report URL in JSON format. /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="reportUrl">The url to report potential XSS attacks to</param> /// <returns>The <see cref="HeaderPolicyCollection"/> for method chaining</returns> public static HeaderPolicyCollection AddXssProtectionReport(this HeaderPolicyCollection policies, string reportUrl) { return(policies.ApplyPolicy(new XssProtectionHeader($"1; report={reportUrl}"))); }
// https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders public static IApplicationBuilder AddCustomSecurityHeaders(this IApplicationBuilder app) { var env = app.ApplicationServices.GetRequiredService <IWebHostEnvironment>(); var policyCollection = new HeaderPolicyCollection() .AddFrameOptionsDeny() .AddXssProtectionBlock() .AddContentTypeOptionsNoSniff() .AddStrictTransportSecurityMaxAge(maxAgeInSeconds: 60 * 60 * 24 * 365) // maxage = one year in seconds .AddReferrerPolicyOriginWhenCrossOrigin() .RemoveServerHeader() .AddContentSecurityPolicy(builder => { if (env.IsProduction()) { builder.AddUpgradeInsecureRequests(); // upgrade-insecure-requests } // builder.AddReportUri() // report-uri: https://report-uri.com // .To("https://report-uri.com"); builder.AddDefaultSrc() .Self(); // Allow AJAX, WebSocket and EventSource connections to: var socketUrl = Startup.Configuration["HostUrl"].ToString().Replace("http://", "ws://", StringComparison.OrdinalIgnoreCase).Replace("https://", "wss://", StringComparison.OrdinalIgnoreCase); var stsUrl = Startup.Configuration["StsAuthority"]; builder.AddConnectSrc() .Self() .From(stsUrl) .From(socketUrl); builder.AddFontSrc() // font-src 'self' .Self() .Data(); builder.AddObjectSrc() // object-src 'none' .None(); builder.AddFormAction() // form-action 'self' .Self(); builder.AddImgSrc() // img-src https: .Self() .Data(); // builder.AddScriptSrc() // script-src 'self' // .Self(); // builder.AddStyleSrc() // style-src 'self' // .Self(); builder.AddUpgradeInsecureRequests(); // upgrade-insecure-requests builder.AddCustomDirective("script-src", "'self' 'unsafe-inline' 'unsafe-eval'"); builder.AddCustomDirective("style-src", "'self' 'unsafe-inline' 'unsafe-eval'"); builder.AddMediaSrc() .Self(); // frame-ancestors 'none' builder.AddFrameAncestors() .None(); builder.AddFrameSource() .From(stsUrl); // You can also add arbitrary extra directives: plugin-types application/x-shockwave-flash" // builder.AddCustomDirective("plugin-types", "application/x-shockwave-flash"); }); app.UseSecurityHeaders(policyCollection); return(app); }
/// <summary> /// Add Strict-Transport-Security max-age=<see paramref="maxAge"/>; includeSubDomains to all requests. /// Tells the user-agent to cache the domain in the STS list for the number of seconds provided and include any sub-domains. /// </summary> /// <param name="policies">The collection of policies</param> /// <param name="maxAgeInSeconds">The maximum number of seconds to cache the domain</param> public static HeaderPolicyCollection AddStrictTransportSecurityMaxAgeIncludeSubDomains(this HeaderPolicyCollection policies, int maxAgeInSeconds = StrictTransportSecurityHeader.OneYearInSeconds) { return(policies.ApplyPolicy(new StrictTransportSecurityHeader($"max-age={maxAgeInSeconds}; includeSubDomains"))); }