Browse Source

Merge pull request #16330 from abpframework/security-headers

Create a document for ABP Security Headers
pull/16367/head
Alper Ebiçoğlu 3 years ago
committed by GitHub
parent
commit
40f2d3e1ef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 45
      docs/en/UI/AspNetCore/Security-Headers.md
  2. 9
      docs/en/docs-nav.json
  3. BIN
      docs/en/images/security-response-headers.png
  4. 21
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs
  5. 9
      framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersOptions.cs
  6. 9
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs

45
docs/en/UI/AspNetCore/Security-Headers.md

@ -0,0 +1,45 @@
# Security Headers
ABP Framework allows you to add frequently used security headers into your application. The following security headers will be added as response headers to your application if you use the `UseAbpSecurityHeaders` middleware:
* `X-Content-Type-Options`: Tells the browser to not try and guess what a mime-type of a resource might be, and to just take what mime-type the server has returned.
* `X-XSS-Protection`: This is a feature of Internet Explorer, Chrome, and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks.
* `X-Frame-Options`: This header can be used to indicate whether or not a browser should be allowed to render a page in a `<iframe>` tag. By specifying this header value as *SAMEORIGIN*, you can make it displayed in a frame on the same origin as the page itself.
* `Content-Security-Policy`: This response header allows you to restrict which resources (such as JavaScript, CSS, images, manifests, etc.) can be loaded, and the URLs that they can be loaded from. This security header will only be added if you configure the `AbpSecurityHeadersOptions` class and enable it.
## Configuration
### AbpSecurityHeadersOptions
`AbpSecurityHeadersOptions` is the main class to enable the `Content-Security-Policy` header, define its value and set other security headers that you want to add to your application.
**Example:**
```csharp
Configure<AbpSecurityHeadersOptions>(options =>
{
options.UseContentSecurityPolicyHeader = true; //false by default
options.ContentSecurityPolicyValue = "object-src 'none'; form-action 'self'; frame-ancestors 'none'";
//adding additional security headers
options.Headers["Referrer-Policy"] = "no-referrer";
});
```
> If the header is the same, the additional security headers you defined take precedence over the default security headers. In other words, it overrides the default security headers' values.
## Security Headers Middleware
Security Headers middleware is an ASP.NET Core request pipeline [middleware](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware) that adds pre-defined security headers to your application, including `X-Content-Type-Options`, `X-XSS-Protection`, and `X-Frame-Options`. Additionally, this middleware also includes those unique security headers in your application if you configure the `AbpSecurityHeadersOptions` as mentioned above.
**Example:**
```csharp
app.UseAbpSecurityHeaders();
```
> You can add this middleware into the `OnApplicationInitialization` method of your module class to register it to the request pipeline. This middleware is already configured in the [ABP Commercial Startup Templates](https://docs.abp.io/en/commercial/latest/startup-templates/index), so you don't need to manually add it if you are using one of these startup templates.
After that, you have registered the `UseAbpSecurityHeaders` middleware into the request pipeline, the defined security headers will be shown in the response headers as in the figure below:
![](../../images/security-response-headers.png)

9
docs/en/docs-nav.json

@ -826,6 +826,15 @@
"path": "UI/AspNetCore/Page-Toolbar-Extensions.md"
}
]
},
{
"text": "Security",
"items": [
{
"text": "Security Headers",
"path": "UI/AspNetCore/Security-Headers.md"
}
]
}
]
},

BIN
docs/en/images/security-response-headers.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

21
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersMiddleware.cs

@ -20,27 +20,38 @@ public class AbpSecurityHeadersMiddleware : IMiddleware, ITransientDependency
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
/*X-Content-Type-Options header tells the browser to not try and “guess” what a mimetype of a resource might be, and to just take what mimetype the server has returned as fact.*/
AddHeaderIfNotExists(context, "X-Content-Type-Options", "nosniff");
AddHeader(context, "X-Content-Type-Options", "nosniff");
/*X-XSS-Protection is a feature of Internet Explorer, Chrome and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks*/
AddHeaderIfNotExists(context, "X-XSS-Protection", "1; mode=block");
AddHeader(context, "X-XSS-Protection", "1; mode=block");
/*The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe> or <object>. SAMEORIGIN makes it being displayed in a frame on the same origin as the page itself. The spec leaves it up to browser vendors to decide whether this option applies to the top level, the parent, or the whole chain*/
AddHeaderIfNotExists(context, "X-Frame-Options", "SAMEORIGIN");
AddHeader(context, "X-Frame-Options", "SAMEORIGIN");
if (Options.Value.UseContentSecurityPolicyHeader)
{
AddHeaderIfNotExists(context, "Content-Security-Policy",
AddHeader(context, "Content-Security-Policy",
Options.Value.ContentSecurityPolicyValue.IsNullOrEmpty()
? "object-src 'none'; form-action 'self'; frame-ancestors 'none'"
: Options.Value.ContentSecurityPolicyValue);
}
foreach (var (key, value) in Options.Value.Headers)
{
AddHeader(context, key, value, true);
}
await next.Invoke(context);
}
protected virtual void AddHeaderIfNotExists(HttpContext context, string key, string value)
protected virtual void AddHeader(HttpContext context, string key, string value, bool overrideIfExists = false)
{
if (overrideIfExists && context.Response.Headers.TryGetValue(key, out _))
{
context.Response.Headers[key] = value;
return;
}
context.Response.Headers.AddIfNotContains(new KeyValuePair<string, StringValues>(key, value));
}
}

9
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/AbpSecurityHeadersOptions.cs

@ -1,3 +1,5 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Security;
public class AbpSecurityHeadersOptions
@ -5,4 +7,11 @@ public class AbpSecurityHeadersOptions
public bool UseContentSecurityPolicyHeader { get; set; }
public string ContentSecurityPolicyValue { get; set; }
public Dictionary<string, string> Headers { get; }
public AbpSecurityHeadersOptions()
{
Headers = new Dictionary<string, string>();
}
}

9
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Headers/SecurityHeadersTestController_Tests.cs

@ -15,6 +15,7 @@ public class SecurityHeadersTestController_Tests : AspNetCoreMvcTestBase
services.Configure<AbpSecurityHeadersOptions>(options =>
{
options.UseContentSecurityPolicyHeader = true;
options.Headers["Referrer-Policy"] = "no-referrer";
});
base.ConfigureServices(context, services);
@ -30,4 +31,12 @@ public class SecurityHeadersTestController_Tests : AspNetCoreMvcTestBase
responseMessage.Headers.ShouldContain(x => x.Key == "X-Content-Type-Options" & x.Value.First().ToString() == "nosniff");
responseMessage.Headers.ShouldContain(x => x.Key == "Content-Security-Policy" & x.Value.First().ToString() == "object-src 'none'; form-action 'self'; frame-ancestors 'none'");
}
[Fact]
public async Task SecurityHeaders_Custom_Headers_Should_Be_Added()
{
var responseMessage = await GetResponseAsync("/SecurityHeadersTest/Get");
responseMessage.Headers.ShouldNotBeEmpty();
responseMessage.Headers.ShouldContain(x => x.Key == "Referrer-Policy" && x.Value.First().ToString() == "no-referrer");
}
}

Loading…
Cancel
Save