1

我正在实现一个自定义 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 新实例传递给中间件。

4

1 回答 1

0

查看HttpContext我收到的空引用异常的堆栈跟踪,似乎中间件是BuildWebHostMain.

我也在使用 Unity,所以我改变了我的构造函数依赖...

IUserRepository userRepository

Func<IUserRepository> userRepositoryFactory

和我的方法调用...

userRepository.FetchLoggedInUser(userIdentifier);

userRepositoryFactory().FetchLoggedInUser(userIdentifier);

方便的是,Unity 会自动生成工厂,因此无需编辑注册。

于 2017-09-27T22:02:40.927 回答