/// <summary> /// Adds support for the <a href="https://developers.facebook.com/docs/plugins/page-plugin">Facebook Page Plugin</a> to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> /// <remarks>Facebook only needs style-src 'sha256-W2kUcrmSyYrtLKKok5R0tuGKVjGmCtnA6wr7AIdSwgU=' rather than unsafe-inline, but if a hash or nonce is used then unsafe-inline is ignored for others that need it (ie Twitter)</remarks> public static CspOptions AddFacebook(this CspOptions options) { var updated = options.Clone(); if (updated.ScriptSrc == null) { updated.ScriptSrc = ScriptCspDirective.Empty; } updated.ScriptSrc = updated.ScriptSrc.AddSource("https://connect.facebook.net"); if (updated.ImgSrc == null) { updated.ImgSrc = CspDirective.Empty; } updated.ImgSrc = updated.ImgSrc.AddSource("https://www.facebook.com"); if (updated.FrameSrc == null) { updated.FrameSrc = CspDirective.Empty; } updated.FrameSrc = updated.FrameSrc.AddSource("https://*.facebook.com"); if (updated.StyleSrc == null) { updated.StyleSrc = StyleCspDirective.Empty; } updated.StyleSrc = updated.StyleSrc.AddUnsafeInline(); return(updated); }
/// <summary> /// Construct a new CspHeader /// </summary> /// <param name="options">The CspOptions to configure the header with</param> public CspHeader(CspOptions options) { options.EnsureNotNull(nameof(options)); Key = $"Content-Security-Policy{(options.IsReportOnly ? "-Report-Only" : string.Empty)}"; Value = string.Concat(options.Directives); }
/// <summary> /// Adds support for Google Maps to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddGoogleMaps(this CspOptions options) { var updated = options.Clone(); if (updated.ScriptSrc == null) { updated.ScriptSrc = ScriptCspDirective.Empty; } updated.ScriptSrc = updated.ScriptSrc.AddSource("https://*.googleapis.com").AddSource("https://maps.gstatic.com").AddUnsafeEval(); if (updated.ImgSrc == null) { updated.ImgSrc = CspDirective.Empty; } updated.ImgSrc = updated.ImgSrc.AddSource("https://*.gstatic.com").AddSource("https://*.googleapis.com").AddSource("https://*.ggpht.com"); if (updated.StyleSrc == null) { updated.StyleSrc = StyleCspDirective.Empty; } updated.StyleSrc = updated.StyleSrc.AddUnsafeInline(); if (updated.FrameSrc == null) { updated.FrameSrc = CspDirective.Empty; } updated.FrameSrc = updated.FrameSrc.AddSource("https://maps.google.co.uk").AddSource("https://www.google.com"); return(updated); }
public static void AddScriptCspHeaders(this HttpResponse response, CspOptions options, string hash) { var csp1part = options.Level == CspLevel.One ? "'unsafe-inline' " : string.Empty; var cspHeader = $"default-src 'none'; script-src {csp1part}'{hash}'"; AddCspHeaders(response.Headers, options, cspHeader); }
/// <summary> /// Adds support for client-side Ordnance Survey maps to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddOrdnanceSurveyMaps(this CspOptions options) { var updated = options.Clone(); if (updated.ScriptSrc == null) { updated.ScriptSrc = ScriptCspDirective.Empty; } updated.ScriptSrc = updated.ScriptSrc.AddSource("https://maps1.eastsussex.gov.uk") .AddSource("https://maps2.eastsussex.gov.uk") .AddSource("https://cdnjs.cloudflare.com") .AddSource("https://serverapi.arcgisonline.com") .AddUnsafeEval(); if (updated.StyleSrc == null) { updated.StyleSrc = StyleCspDirective.Empty; } updated.StyleSrc = updated.StyleSrc.AddSource("https://serverapi.arcgisonline.com").AddUnsafeInline(); if (updated.ImgSrc == null) { updated.ImgSrc = CspDirective.Empty; } updated.ImgSrc = updated.ImgSrc.AddSource("https://maps1.eastsussex.gov.uk").AddSource("https://maps2.eastsussex.gov.uk").AddSource("https://serverapi.arcgisonline.com"); return(updated); }
public void ManyOptions_ResultIsCorrect() { var options = new CspOptions { Default = new CspDefaultSrcOptions { AllowSelf = true }, Img = new CspImgSrcOptions { AllowAny = true }, Media = new CspMediaSrcOptions { AllowedSources = new List <string> { "media1.com", "media2.com" } }, Script = new CspScriptSrcOptions { AllowedSources = new List <string> { "userscripts.example.com" } } }; var(headerName, headerValue) = options.ToString(null); Assert.Equal("Content-Security-Policy", headerName); Assert.Equal("default-src 'self';script-src userscripts.example.com;img-src *;media-src media1.com media2.com", headerValue); }
/// <summary> /// Adds middleware for using CSP, which adds the Content-Security-Policy header. /// </summary> /// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> /// <param name="csp">Value to be set for Content-Security-Policy header.</param> /// <returns></returns> public static IApplicationBuilder UseCsp(this IApplicationBuilder app, string csp) { CspOptions options = new CspOptions { Content = csp }; return(app.UseMiddleware <CspMiddleware>(options)); }
public void EnableSandbox_EnablesTheSandbox() { var builder = new CspBuilder(); builder.EnableSandbox(); CspOptions options = builder.BuildCspOptions(); Assert.True(options.EnableSandbox); }
public void SetReportOnly_SetsReportOnlyToTrue() { var builder = new CspBuilder(); builder.SetReportOnly(); CspOptions options = builder.BuildCspOptions(); Assert.True(options.ReportOnly); }
public void SetUpgradeInsecureRequests_SetsUpgradeInsecureRequestsToTrue() { var builder = new CspBuilder(); builder.SetUpgradeInsecureRequests(); CspOptions options = builder.BuildCspOptions(); Assert.True(options.UpgradeInsecureRequests); }
/// <summary> /// Adds middleware for using CSP, which adds the Content-Security-Policy header. /// </summary> /// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> /// <param name="builderAction">A delegate used for setting up the <see cref="CspOptionsBuilder"/>.</param> /// <returns></returns> public static IApplicationBuilder UseCsp(this IApplicationBuilder app, Action <CspOptionsBuilder> builderAction) { CspOptionsBuilder builder = new CspOptionsBuilder(); builderAction(builder); CspOptions options = builder.Build(); return(app.UseMiddleware <CspMiddleware>(options)); }
public void SetBlockAllMixedContent_SetsBlockAllMixedContentToTrue() { var builder = new CspBuilder(); builder.SetBlockAllMixedContent(); CspOptions options = builder.BuildCspOptions(); Assert.True(options.BlockAllMixedContent); }
public void ReportViolationsTo_SetsTheReportUri() { var builder = new CspBuilder(); builder.ReportViolationsTo("/somewhere"); CspOptions options = builder.BuildCspOptions(); Assert.Equal("/somewhere", options.ReportUri); }
public void IncludeXHeader_SetsIncludeXHeaderToTrue() { var builder = new CspBuilder(); builder.IncludeXHeader(); CspOptions options = builder.BuildCspOptions(); Assert.True(options.IncludeXHeader); }
public void UpgradeInsecureRequests_ValueIsCorrect() { var options = new CspOptions { UpgradeInsecureRequests = true }; string policy = options.ToString(null).headerValue; Assert.Equal("upgrade-insecure-requests", policy); }
public void BlockAllMixedContent_ValueIsCorrect() { var options = new CspOptions { BlockAllMixedContent = true }; string policy = options.ToString(null).headerValue; Assert.Equal("block-all-mixed-content", policy); }
public static void AddCspHeaders(this IHeaderDictionary headers, CspOptions options, string cspHeader) { if (!headers.ContainsKey("Content-Security-Policy")) { headers.Add("Content-Security-Policy", cspHeader); } if (options.AddDeprecatedHeader && !headers.ContainsKey("X-Content-Security-Policy")) { headers.Add("X-Content-Security-Policy", cspHeader); } }
/// <summary> /// Adds support for Google Content Experiments to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddGoogleContentExperiments(this CspOptions options) { var updated = options.Clone(); if (updated.ScriptSrc == null) { updated.ScriptSrc = ScriptCspDirective.Empty; } updated.ScriptSrc = updated.ScriptSrc.AddUnsafeInline(); return(updated); }
/// <summary> /// Adds support for server-side Ordnance Survey maps to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddOldOrdnanceSurveyMaps(this CspOptions options) { var updated = options.Clone(); if (updated.ImgSrc == null) { updated.ImgSrc = CspDirective.Empty; } updated.ImgSrc = updated.ImgSrc.AddSource("https://maps2.eastsussex.gov.uk"); return(updated); }
public static void AddStyleCspHeaders(this HttpResponse response, CspOptions options, string hash, string frameSources) { var csp1part = options.Level == CspLevel.One ? "'unsafe-inline' " : string.Empty; var cspHeader = $"default-src 'none'; style-src {csp1part}'{hash}'"; if (!string.IsNullOrEmpty(frameSources)) { cspHeader += $"; frame-src {frameSources}"; } AddCspHeaders(response.Headers, options, cspHeader); }
public void ContentSecurityPolicyMiddleware_adds_policy_from_startup() { var context = new DefaultHttpContext(); context.Response.ContentType = "text/html"; var environment = new Mock <IHostingEnvironment>(); var policyFromStartup = new CspOptions().AddYouTube(); ContentSecurityPolicyMiddleware.AddHeader(context, environment.Object, policyFromStartup, new List <ContentSecurityPolicyDependency>()); Assert.Contains("https://www.youtube-nocookie.com", context.Response.Headers["Content-Security-Policy"].ToString()); }
/// <summary> /// Adds support for an ESCIS search widget to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddEscis(this CspOptions options) { var updated = options.Clone(); if (updated.FrameSrc == null) { updated.FrameSrc = CspDirective.Empty; } updated.FrameSrc = updated.FrameSrc.AddSource("https://www.escis.org.uk"); return(updated); }
/// <summary> /// Adds support for an East Sussex 1Space search widget to an existing Content Security Policy /// </summary> /// <param name="options"></param> /// <returns></returns> public static CspOptions AddEastSussex1Space(this CspOptions options) { var updated = options.Clone(); if (updated.ImgSrc == null) { updated.ImgSrc = CspDirective.Empty; } updated.ImgSrc = updated.ImgSrc.AddSource("https://1space.eastsussex.gov.uk"); return(updated); }
public void Invoked_StringAdded() { //Arrange CspOptionsBuilder builder = new CspOptionsBuilder(); //Act builder.BlockAllMixedContent(); //Assert CspOptions options = builder.Build(); Assert.Equal("block-all-mixed-content", options.Content); }
public void Invoked_StringAdded() { //Arrange CspOptionsBuilder builder = new CspOptionsBuilder(); //Act builder.UpgradeInsecureRequests(); //Assert CspOptions options = builder.Build(); Assert.Equal("upgrade-insecure-requests", options.Content); }
public void BaseUriSelf_ValueIsCorrect() { var options = new CspOptions { BaseUri = new CspBaseUriOptions { AllowSelf = true } }; string policy = options.ToString(null).headerValue; Assert.Equal("base-uri 'self'", policy); }
/// <summary> /// Adds support for localhost URLs to any directive of an existing Content Security Policy that already supports another source /// </summary> /// <param name="options"></param> /// <returns></returns> /// <remarks>For use in development</remarks> public static CspOptions AddLocalhost(this CspOptions options) { var updated = options.Clone(); if (updated.ChildSrc != null) { updated.ChildSrc = updated.ChildSrc.AddSource("https://localhost:*"); } if (updated.ConnectSrc != null) { updated.ConnectSrc = updated.ConnectSrc.AddSource("https://localhost:*"); } if (updated.FontSrc != null) { updated.FontSrc = updated.FontSrc.AddSource("https://localhost:*"); } if (updated.FrameSrc != null) { updated.FrameSrc = updated.FrameSrc.AddSource("https://localhost:*"); } if (updated.ImgSrc != null) { updated.ImgSrc = updated.ImgSrc.AddSource("https://localhost:*"); } if (updated.ManifestSrc != null) { updated.ManifestSrc = updated.ManifestSrc.AddSource("https://localhost:*"); } if (updated.MediaSrc != null) { updated.MediaSrc = updated.MediaSrc.AddSource("https://localhost:*"); } if (updated.ObjectSrc != null) { updated.ObjectSrc = updated.ObjectSrc.AddSource("https://localhost:*"); } if (updated.ScriptSrc != null) { updated.ScriptSrc = updated.ScriptSrc.AddSource("https://localhost:*"); } if (updated.StyleSrc != null) { updated.StyleSrc = updated.StyleSrc.AddSource("https://localhost:*"); } if (updated.WorkerSrc != null) { updated.WorkerSrc = updated.WorkerSrc.AddSource("https://localhost:*"); } return(updated); }
public void WithoutReportOnly_HeaderNameIsCorrect() { var options = new CspOptions { Default = new CspDefaultSrcOptions { AllowAny = true } }; var(headerName, _) = options.ToString(null); Assert.Equal("Content-Security-Policy", headerName); }
public void SomeBuildersReturnedDirectives_AllDirectivesIncluded() { //Arrange CspOptionsBuilder builder = new CspOptionsBuilder(); //Act builder.ConnectSources.AllowSelf(); builder.ScriptSources.AllowHosts("https://example.com"); builder.Sandbox.AllowModals(); //Assert CspOptions result = builder.Build(); Assert.Equal("connect-src 'self'; script-src https://example.com; sandbox allow-modals", result.Content); }
public void UpgradeInsecureRequestsAndDefaultHttps_ValueIsCorrect() { var options = new CspOptions { UpgradeInsecureRequests = true, Default = new CspDefaultSrcOptions { AllowOnlyHttps = true } }; string policy = options.ToString(null).headerValue; Assert.Equal("upgrade-insecure-requests;default-src https:", policy); }
public void Setup() { _options = new CspOptions(); }