聊聊spring cloud gateway的SecureHeadersGatewayFilter

本文主要研究下spring cloud gateway的SecureHeadersGatewayFilter

GatewayAutoConfiguration

@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
    //......
    @Bean
    public SecureHeadersGatewayFilterFactory secureHeadersGatewayFilterFactory(SecureHeadersProperties properties) {
        return new SecureHeadersGatewayFilterFactory(properties);
    }
    //......
}

SecureHeadersProperties

配置项

    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'",
      "name": "spring.cloud.gateway.filter.secure-headers.content-security-policy",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "nosniff",
      "name": "spring.cloud.gateway.filter.secure-headers.content-type-options",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "noopen",
      "name": "spring.cloud.gateway.filter.secure-headers.download-options",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "DENY",
      "name": "spring.cloud.gateway.filter.secure-headers.frame-options",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "none",
      "name": "spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "no-referrer",
      "name": "spring.cloud.gateway.filter.secure-headers.referrer-policy",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "max-age=631138519",
      "name": "spring.cloud.gateway.filter.secure-headers.strict-transport-security",
      "type": "java.lang.String"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.factory.SecureHeadersProperties",
      "defaultValue": "1 ; mode=block",
      "name": "spring.cloud.gateway.filter.secure-headers.xss-protection-header",
      "type": "java.lang.String"
    }

实体类

spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/filter/factory/SecureHeadersProperties.java

@ConfigurationProperties("spring.cloud.gateway.filter.secure-headers")
public class SecureHeadersProperties {
    public static final String X_XSS_PROTECTION_HEADER_DEFAULT = "1 ; mode=block";
    public static final String STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT = "max-age=631138519"; //; includeSubDomains preload")
    public static final String X_FRAME_OPTIONS_HEADER_DEFAULT = "DENY"; //SAMEORIGIN = ALLOW-FROM
    public static final String X_CONTENT_TYPE_OPTIONS_HEADER_DEFAULT = "nosniff";
    public static final String REFERRER_POLICY_HEADER_DEFAULT = "no-referrer"; //no-referrer-when-downgrade = origin = origin-when-cross-origin = same-origin = strict-origin = strict-origin-when-cross-origin = unsafe-url
    public static final String CONTENT_SECURITY_POLICY_HEADER_DEFAULT = "default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'";
    public static final String X_DOWNLOAD_OPTIONS_HEADER_DEFAULT = "noopen";
    public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT = "none";

    private String xssProtectionHeader = X_XSS_PROTECTION_HEADER_DEFAULT;
    private String strictTransportSecurity = STRICT_TRANSPORT_SECURITY_HEADER_DEFAULT;
    private String frameOptions = X_FRAME_OPTIONS_HEADER_DEFAULT;
    private String contentTypeOptions = X_CONTENT_TYPE_OPTIONS_HEADER_DEFAULT;
    private String referrerPolicy = REFERRER_POLICY_HEADER_DEFAULT;
    private String contentSecurityPolicy = CONTENT_SECURITY_POLICY_HEADER_DEFAULT;
    private String downloadOptions = X_DOWNLOAD_OPTIONS_HEADER_DEFAULT;
    private String permittedCrossDomainPolicies = X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER_DEFAULT;

    //......

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("SecureHeadersProperties{");
        sb.append("xssProtectionHeader='").append(xssProtectionHeader).append('\'');
        sb.append(", strictTransportSecurity='").append(strictTransportSecurity).append('\'');
        sb.append(", frameOptions='").append(frameOptions).append('\'');
        sb.append(", contentTypeOptions='").append(contentTypeOptions).append('\'');
        sb.append(", referrerPolicy='").append(referrerPolicy).append('\'');
        sb.append(", contentSecurityPolicy='").append(contentSecurityPolicy).append('\'');
        sb.append(", downloadOptions='").append(downloadOptions).append('\'');
        sb.append(", permittedCrossDomainPolicies='").append(permittedCrossDomainPolicies).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

SecureHeadersGatewayFilterFactory

spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/filter/factory/SecureHeadersGatewayFilterFactory.java

/**
 * https://blog.appcanary.com/2017/http-security-headers.html
 * @author Spencer Gibb
 */
public class SecureHeadersGatewayFilterFactory extends AbstractGatewayFilterFactory {

    public static final String X_XSS_PROTECTION_HEADER = "X-Xss-Protection";
    public static final String STRICT_TRANSPORT_SECURITY_HEADER = "Strict-Transport-Security";
    public static final String X_FRAME_OPTIONS_HEADER = "X-Frame-Options";
    public static final String X_CONTENT_TYPE_OPTIONS_HEADER = "X-Content-Type-Options";
    public static final String REFERRER_POLICY_HEADER = "Referrer-Policy";
    public static final String CONTENT_SECURITY_POLICY_HEADER = "Content-Security-Policy";
    public static final String X_DOWNLOAD_OPTIONS_HEADER = "X-Download-Options";
    public static final String X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER = "X-Permitted-Cross-Domain-Policies";

    private final SecureHeadersProperties properties;

    public SecureHeadersGatewayFilterFactory(SecureHeadersProperties properties) {
        this.properties = properties;
    }

    @Override
    public GatewayFilter apply(Object config) {
        //TODO: allow args to override properties

        return (exchange, chain) -> {
            HttpHeaders headers = exchange.getResponse().getHeaders();

            //TODO: allow header to be disabled
            headers.add(X_XSS_PROTECTION_HEADER, properties.getXssProtectionHeader());
            headers.add(STRICT_TRANSPORT_SECURITY_HEADER, properties.getStrictTransportSecurity());
            headers.add(X_FRAME_OPTIONS_HEADER, properties.getFrameOptions());
            headers.add(X_CONTENT_TYPE_OPTIONS_HEADER, properties.getContentTypeOptions());
            headers.add(REFERRER_POLICY_HEADER, properties.getReferrerPolicy());
            headers.add(CONTENT_SECURITY_POLICY_HEADER, properties.getContentSecurityPolicy());
            headers.add(X_DOWNLOAD_OPTIONS_HEADER, properties.getDownloadOptions());
            headers.add(X_PERMITTED_CROSS_DOMAIN_POLICIES_HEADER, properties.getPermittedCrossDomainPolicies());

            return chain.filter(exchange);
        };
    }
}

可以看到该filter往response的header添加一系列的security相关的header

小结

SecureHeadersGatewayFilter往response添加了如下header

  • X-Xss-Protection spring.cloud.gateway.filter.secure-headers.xss-protection-header=1 ; mode=block
  • Strict-Transport-Security spring.cloud.gateway.filter.secure-headers.strict-transport-security=max-age=631138519
  • X-Frame-Options spring.cloud.gateway.filter.secure-headers.frame-options=DENY
  • X-Content-Type-Options spring.cloud.gateway.filter.secure-headers.content-type-options=nosniff
  • Referrer-Policy spring.cloud.gateway.filter.secure-headers.referrer-policy=no-referrer
  • Content-Security-Policy spring.cloud.gateway.filter.secure-headers.content-security-policy=default-src ‘self’ https:; font-src ‘self’ https: data:; img-src ‘self’ https: data:; object-src ‘none’; script-src https:; style-src ‘self’ https: ‘unsafe-inline’
  • X-Download-Options spring.cloud.gateway.filter.secure-headers.download-options=noopen
  • X-Permitted-Cross-Domain-Policies spring.cloud.gateway.filter.secure-headers.permitted-cross-domain-policies=none

doc

  • Everything you need to know about HTTP security headers
  • 112.14 SecureHeaders GatewayFilter Factory

原文发布于微信公众号 - 码匠的流水账(geek_luandun)

原文发表时间:2018-06-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏芋道源码1024

MyBastis 三种批量插入方式的性能比较

数据库使用的是sqlserver,JDK版本1.8,运行在SpringBoot环境下

4293
来自专栏A周立SpringCloud

Spring Cloud Edgware新特性之八:Zuul回退的改进

Spring Cloud Edgware对Hystrix回退的逻辑进行了一些改进。本文将信息探讨新旧版本的回退操作,并分析的原因及改进后的优势。 Dalston...

2916
来自专栏菩提树下的杨过

ExtJs学习笔记(6)_可分页的GridPanel

一.WCF部分 1.通过查看官方的示例得知,分页数据源需要一个记录总数值,为保持通用性,这里借鉴jillZhang的文章,把他写的通用类PageData拿过来...

2188
来自专栏.NET开发者社区

一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](二)

在本系列第一篇《一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](一)》中,我为大家介绍...

29610
来自专栏解Bug之路

MySql之自动生成CRUD代码

MyBatis能够通过获取MySql中的information_schema从而获取表的字段等信息,最后通过这些信息生成代码。 笔者受此启发,将MyBatis...

1223
来自专栏我是攻城师

ElasticSearch之Java Api聚合分组实战

4536
来自专栏菩提树下的杨过

Spring Security笔记:登录尝试次数限制

今天在前面一节的基础之上,再增加一点新内容,默认情况下Spring Security不会对登录错误的尝试次数做限制,也就是说允许暴力尝试,这显然不够安全,下面的...

4695
来自专栏逸鹏说道

ExecuteReader在执行有输出参数的存储过程时拿不到输出参数

异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 后期会在博客首发更新:http://dnt...

3577
来自专栏向治洪

将图库的图片剪切并保存

最近有些用户反映保存图片之后在系统图库找不到保存的图片,遂决定彻底查看并解决下。 Adnroid中保存图片的方法可能有如下两种: 第一种是自己写方法,如下代...

23910
来自专栏软件工程师成长笔记

Mybatis分页插件PageHelper的使用详解

如果你也在用Mybatis,建议尝试该分页插件,个人感觉这个是最方便,超好用的分页插件。 该插件目前支持Oracle,Mysql,MariaDB,SQLite...

1.5K3

扫码关注云+社区

领取腾讯云代金券