我正在实现一个自定义 owin 中间件以CSP
在响应标头中添加标头(内容安全策略)。为了CSP
工作,中间件需要为每个请求创建一个唯一的 nonce 值。所以我有NonceService
它创造了 nonce 价值。自定义 OWIN 中间件依赖于 NonceService。
但是我的问题是我无法为每个请求注册自定义中间件。
当我调试时,我注意到 OWIN没有为每个请求创建自定义中间件的新实例,因为所有请求都使用了相同的 nonce 值。
下面是我的代码
随机数服务
public interface INonceService
{
string GetNonce();
}
public class NonceService : INonceService
{
private static readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
private readonly string _nonce;
public NonceService(int nonceByteAmount = 32)
{
var nonceBytes = new byte[nonceByteAmount];
_rng.GetBytes(nonceBytes);
_nonce = Convert.ToBase64String(nonceBytes);
}
public string GetNonce()
{
return _nonce;
}
}
OWIN 中间件和扩展
public class SecurityHeaderMiddleware : OwinMiddleware
{
private readonly INonceService _nonceService = null;
public SecurityHeaderMiddleware(OwinMiddleware next, INonceService nonceService) : base(next)
{
_nonceService = nonceService;
}
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
var nonce = _nonceService.GetNonce();
var csp = BuildCSPHeader(nonce);
context.Response.Headers.Add(key, csp);
}
}
public static class OwinExtensions
{
private const string SecurityHeaderRegistrationKey = "SecurityHeaders";
public static IAppBuilder UseSecurityHeader(this IAppBuilder app, INonceService nonceService)
{
if (app == null)
throw new ArgumentNullException("app");
if (app.Properties.ContainsKey(SecurityHeaderRegistrationKey))
return app;
app.Use<SecurityHeaderMiddleware>(nonceService);
app.Properties.Add(SecurityHeaderRegistrationKey, true);
return app;
}
}
我使用 Unity 作为容器,所以我使用注册 INonceServicePerRequestLifetimeManager
container.RegisterType<INonceService, NonceService>(new PerRequestLifetimeManager(), new InjectionConstructor(32));
我在 startup.cs 中向 OWIN 注册了我的自定义中间件
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var nonceService = ServiceLocator.Current.GetInstance<INonceService>();
app.UseSecurityHeader(nonceService);
}
}
注意 如果无法创建每个请求的 OWIN 中间件,那么至少我应该如何将每个请求的 NonceService 新实例传递给中间件。