我正在实现一个自定义owin中间件,以在响应头中添加CSP
标头(内容安全策略)。要使CSP
起作用,中间件需要为每个请求创建唯一的随机数值。所以我有NonceService
创建nonce值。自定义OWIN中间件依赖于NonceService。
但是我的问题是我无法按要求注册自定义中间件。
当我调试时,我注意到OWIN NOT 为每个请求创建自定义中间件的新实例,并且因为所有请求都使用相同的nonce值。
以下是我的代码
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 Middleware&扩展
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作为conatiner,所以我使用PerRequestLifetimeManager
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实例传递给中间件。
答案 0 :(得分:0)
查看我收到的HttpContext
空引用异常时的堆栈跟踪,似乎中间件是在BuildWebHost
的{{1}}中构建的。
我也在使用Unity,所以我改变了构造函数依赖...
Main
到
IUserRepository userRepository
我的方法来自......
Func<IUserRepository> userRepositoryFactory
到
userRepository.FetchLoggedInUser(userIdentifier);
方便地,Unity会自动生成工厂,因此无需编辑注册。