ActionFilterAttribute-当订单重要时

时间:2019-04-15 13:13:04

标签: c# asp.net asp.net-core .net-core

背景

我刚刚写了一个小的ActionFilterAttribute(asp.net核心v2.2 + c#),在响应中添加了安全标题:

public class SecurityHeadersAttribute : ActionFilterAttribute
    {
        public const string X_FRMAE_OPTIONS = "X-Frame-Options";
        public const string X_FRMAE_OPTIONS_ALLOW_FROM = "ALLOW-FROM"; // e.g. "ALLOW-FROM {uri}"
        public const string X_FRMAE_OPTIONS_SAMEORIGIN = "SAMEORIGIN";
        public const string X_FRMAE_OPTIONS_DENY = "DENY";

        public const string X_XSS_PROTECTION = "X-XSS-Protection";
        public const string X_XSS_PROTECTION_DEFAULT = "1; mode=block";

        public const string X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
        public const string X_CONTENT_TYPE_OPTIONS_DEFAULT = "nosniff";

        public const string STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security";
        public const string STRICT_TRANSPORT_SECURITY_DEFAULT = "max-age=31536000; includeSubDomains"; //60 * 60 * 24 * 365

        public const string REFERRER_POLICY = "Referrer-Policy";
        public const string REFERRER_POLICY_ORIGIN = "Origin";
        public const string REFERRER_POLICY_STRICT_ORIGIN_WHEN_CROSS_ORIGIN = "strict-origin-when-cross-origin";

        public const string FEATURE_POLICY = "Feature-Policy";
        public const string FEATURE_POLICY_DEFAULT = "microphone 'none';";

        public const string CONTENT_SECURITY_POLICY = "Content-Security-Policy";
        public const string CONTENT_SECURITY_POLICY_DEFAULT = "object-src 'none';form-action 'none'; frame-ancestors 'none';";

        public SecurityHeadersAttribute(
                string xFrameOptions = X_FRMAE_OPTIONS_SAMEORIGIN, 
                string xssProtection = X_XSS_PROTECTION_DEFAULT, 
                string contentTypeOptions = CONTENT_SECURITY_POLICY_DEFAULT, 
                string strictTransportSecurity = STRICT_TRANSPORT_SECURITY_DEFAULT,
                string referrerPolicy = REFERRER_POLICY_ORIGIN,
                string featurePolicy = FEATURE_POLICY_DEFAULT,
                string contentSecurityPolicy = CONTENT_SECURITY_POLICY_DEFAULT
            )
        {
            this.FrameOptions = xFrameOptions;
            this.XSSProtection = xssProtection;
            this.ContentTypeOptions = contentTypeOptions;
            this.StrictTransportSecurity = strictTransportSecurity;
            this.ReferrerPolicy = referrerPolicy;
            this.FeaturePolicy = featurePolicy;
            this.ContentSecurityPolicy = contentSecurityPolicy;
        }

        public string FrameOptions { get; set; }
        public string XSSProtection { get; set; }
        public string ContentTypeOptions { get; set; }
        public string StrictTransportSecurity { get; set; }
        public string ReferrerPolicy { get; set; }
        public string FeaturePolicy { get; set; }
        public string ContentSecurityPolicy { get; set; }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            if (!string.IsNullOrEmpty(FrameOptions))
                filterContext.HttpContext.Response.Headers[X_FRMAE_OPTIONS] = FrameOptions;

            if (!string.IsNullOrEmpty(XSSProtection))
                filterContext.HttpContext.Response.Headers[X_XSS_PROTECTION] = XSSProtection;

            if (!string.IsNullOrEmpty(ContentTypeOptions))
                filterContext.HttpContext.Response.Headers[X_CONTENT_TYPE_OPTIONS] = ContentTypeOptions;

            if (!string.IsNullOrEmpty(StrictTransportSecurity))
                filterContext.HttpContext.Response.Headers[STRICT_TRANSPORT_SECURITY] = StrictTransportSecurity;

            if (!string.IsNullOrEmpty(ReferrerPolicy))
                filterContext.HttpContext.Response.Headers[REFERRER_POLICY] = ReferrerPolicy;

            if (!string.IsNullOrEmpty(FeaturePolicy))
                filterContext.HttpContext.Response.Headers[FEATURE_POLICY] = FeaturePolicy;

            if (!string.IsNullOrEmpty(ContentSecurityPolicy))
                filterContext.HttpContext.Response.Headers[CONTENT_SECURITY_POLICY] = ContentSecurityPolicy;

            base.OnResultExecuting(filterContext);
        }

您可以输入Controller

[SecurityHeaders]
public class MyController : Controller
{
}

或在Action上。像这样:

public class MyController : Controller
{
    [SecurityHeaders]
    public ActionResult MyAction() 
    {
        // My code here.
    }
}

直到现在,一切正常。

问题

如果我在控制器级别和操作级别上都具有属性[SecurityHeaders],则操作级别应该获胜,并且是唯一放置标头的属性。

因此,如果我的代码如下:

[SecurityHeaders(/* DEFAULT PARAMS */)]
public class MyController : Controller
{
    [SecurityHeaders (xFrameOptions: null)] // <---- only this should take place
    public ActionResult MyAction() 
    {
        // My code here.
    }
}

我希望默认标头应打印到响应中,但X-FRAME-OPTION将不存在。

Acutal,使用默认值xFrameOptions调用类级别属性。

问题:

如何使操作级别属性强于类级别?

1 个答案:

答案 0 :(得分:0)

然后您可能应该更改构造函数,使其不具有标头参数的默认值,而是使其类似

   public SecurityHeadersAttribute(string xFrameOptions)
    {
        this.FrameOptions = xFrameOptions;
    } 

因此,您在OnResultExecuting()以下的细分受众群中永远不会得到评估

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (!string.IsNullOrEmpty(FrameOptions))
            filterContext.HttpContext.Response.Headers[X_FRMAE_OPTIONS] = FrameOptions;