我刚刚写了一个小的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
调用类级别属性。
如何使操作级别属性强于类级别?
答案 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;