1 Refused to display ‘url’ in a frame because it set 'X-Frame-Options' to 'sameorigi

进在开发公司的文件中心组件,提供各个子系统的附件上传下载、预览、版本更新等功能,前端在今天突然给我发一张图,说预览缩略图遇到问题了,然后发了个截图给我:1 Refused to display ‘url’ in a frame because it set 'X-Frame-Options'  to 'sameorigi

这很明显是一个跨域问题,

X-Frame-Options HTTP 响应头是用来给浏览器指示允许一个页面可否在 <frame>, <iframe>或者 <object> 中展现的标记。网站可以使用此功能,来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

X-Frame-Options 有三个值:

DENY

  表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。

SAMEORIGIN

  表示该页面可以在相同域名页面的 frame 中展示(一般默认是这种)。

ALLOW-FROM uri

  表示该页面可以在指定来源的 frame 中展示。

此处很明显需要在中间件里面修改一下响应头的X-Frame-Options属性,core的中间件流程如下:

1 Refused to display ‘url’ in a frame because it set 'X-Frame-Options'  to 'sameorigi

所以我们需要实现一个响应头的增删集合类:

    /// <summary>
    /// 响应头的增删集合
    /// </summary>
    public class SecurityHeadersPolicy
    {
        public IDictionary<string, string> SetHeaders { get; }
             = new Dictionary<string, string>();

        public ISet<string> RemoveHeaders { get; }
            = new HashSet<string>();
    }

 

然后实现一个增删响应头的中间件:

/// <summary>
    /// 中间件实现
    /// </summary>
    public class SecurityHeadersMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly SecurityHeadersPolicy _policy;

        public SecurityHeadersMiddleware(RequestDelegate next, SecurityHeadersPolicy policy)
        {
            _next = next;
            _policy = policy;
        }

        public async Task Invoke(HttpContext context)
        {
            IHeaderDictionary headers = context.Response.Headers;

            foreach (var headerValuePair in _policy.SetHeaders)
            {
                headers[headerValuePair.Key] = headerValuePair.Value;
            }

            foreach (var header in _policy.RemoveHeaders)
            {
                headers.Remove(header);
            }

            await _next(context);
        }
    }

提供响应头的增删方法:

    /// <summary>
    /// 响应头的增删方法
    /// </summary>
    public class SecurityHeadersBuilder
    {
        private readonly SecurityHeadersPolicy _policy = new SecurityHeadersPolicy();
        public SecurityHeadersBuilder AddCustomHeader(string header, string value)
        {
            _policy.SetHeaders[header] = value;
            return this;
        }
        public SecurityHeadersBuilder RemoveHeader(string header)
        {
            _policy.RemoveHeaders.Add(header);
            return this;
        }
        public SecurityHeadersPolicy Build()
        {
            return _policy;
        }
    }

然后我们需要一个中间件的拓展方法:

    /// <summary>
    /// 中间件拓展方法
    /// </summary>
    public static class UseSecurityHeaders
    {
        public static IApplicationBuilder UseSecurityHeadersMiddleware(this IApplicationBuilder app, SecurityHeadersBuilder builder)
        {
            SecurityHeadersPolicy policy = builder.Build();
            return app.UseMiddleware<SecurityHeadersMiddleware>(policy);
        }
    }

然后就是在startup的Configure方法中注册我们的中间件:

            //允许iframe嵌入资源
            app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
              .AddCustomHeader("X-Frame-Options", "AllowAll")
            );

我在这里使用的值是“AllowAll” 而不是“ALLOW-FROM uri” 是为了方便测试,如果开发的话应该是需要进行配置的,到这里再嵌入网页即可成功。

上一篇:You're seeing this error because you have DEBUG = True in your Django settings file. Change tha


下一篇:对象