Skip to content

SecureHeaders GatewayFilter Factory

概述

SecureHeaders 过滤器工厂是 Spring Cloud Gateway 提供的一个重要安全组件,它会在 HTTP 响应中自动添加多个安全头部,帮助防御常见的 Web 安全威胁。这些安全头部遵循了业界最佳实践,能够有效提升应用的安全性。

业务场景与问题解决

在现代 Web 应用中,安全问题日益突出。以下是 SecureHeaders 过滤器解决的典型安全问题:

1. XSS 攻击防护

恶意用户可能注入 JavaScript 代码,窃取用户信息或执行恶意操作。

2. 内容类型嗅探攻击

浏览器可能错误地解释文件类型,导致安全漏洞。

3. 点击劫持攻击

恶意网站通过 iframe 嵌入目标网站,欺骗用户点击。

4. 中间人攻击

在不安全的网络环境中,攻击者可能截获或篡改通信内容。

默认安全头部

SecureHeaders 过滤器默认添加以下安全头部:

具体头部说明

安全头部默认值作用
X-XSS-Protection1 (mode=block)启用浏览器内置的 XSS 过滤器
Strict-Transport-Securitymax-age=631138519强制使用 HTTPS 连接
X-Frame-OptionsDENY禁止页面被嵌入到 frame 中
X-Content-Type-Optionsnosniff防止浏览器进行 MIME 类型嗅探
Referrer-Policyno-referrer不发送引用页面信息
Content-Security-Policy详见下方定义内容安全策略
X-Download-Optionsnoopen防止 IE 自动打开下载文件
X-Permitted-Cross-Domain-Policiesnone禁止跨域策略文件

默认的 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'`

配置方式

1. 全局配置

自定义默认值

可以在 spring.cloud.gateway.filter.secure-headers 命名空间下配置各个安全头部的值:

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # 自定义 XSS 保护策略
          xss-protection-header: "1; mode=block"
          # 设置 HSTS 最大存活时间(1年)
          strict-transport-security: "max-age=31536000; includeSubDomains"
          # 允许同源页面嵌入
          frame-options: "SAMEORIGIN"
          # 设置内容类型选项
          content-type-options: "nosniff"
          # 设置引用策略
          referrer-policy: "strict-origin-when-cross-origin"
          # 自定义内容安全策略
          content-security-policy: "default-src 'self'; script-src 'self' 'unsafe-inline'"
          # IE 下载选项
          download-options: "noopen"
          # 跨域策略
          permitted-cross-domain-policies: "none"
kotlin
@Configuration
class GatewayConfig {

    /**
     * 配置全局安全头部过滤器
     * 通过代码方式自定义安全头部配置
     */
    @Bean
    fun secureHeadersFilter(): GlobalFilter {
        return GlobalFilter { exchange, chain ->
            // 在响应中添加自定义安全头部
            exchange.response.headers.apply {
                set("X-XSS-Protection", "1; mode=block")
                set("X-Frame-Options", "SAMEORIGIN")
                set("X-Content-Type-Options", "nosniff")
                set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
                set("Referrer-Policy", "strict-origin-when-cross-origin")
            }
            chain.filter(exchange)
        }
    }
}

禁用特定头部

有时我们需要禁用某些默认的安全头部,可以使用 disable 属性:

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # 禁用 X-Frame-Options 和 Strict-Transport-Security
          disable: x-frame-options,strict-transport-security

禁用安全头部时需要使用小写的完整名称,如 `x-frame-options` 而不是 `X-Frame-Options`。

2. 路由级别配置

可以为特定路由配置 SecureHeaders 过滤器,路由级别的配置会覆盖全局默认配置:

yaml
spring:
  cloud:
    gateway:
      routes:
        # 为管理后台配置更严格的安全策略
        - id: admin_route
          uri: http://admin.example.org
          predicates:
            - Path=/admin/**
          filters:
            - name: SecureHeaders
              args:
                # 禁用框架嵌入
                frame-options: "DENY"
                # 更严格的内容安全策略
                content-security-policy: "default-src 'self'; script-src 'self'; style-src 'self'"

        # 为 API 路由配置适合的安全策略
        - id: api_route
          uri: http://api.example.org
          predicates:
            - Path=/api/**
          filters:
            - name: SecureHeaders
              args:
                # 允许跨域访问,禁用某些不必要的头部
                disable: x-frame-options
                referrer-policy: "origin-when-cross-origin"
kotlin
@Configuration
class RouteConfig {

    /**
     * 使用 Kotlin DSL 配置路由和安全头部
     */
    @Bean
    fun routeLocator(builder: RouteLocatorBuilder): RouteLocator {
        return builder.routes {
            // 管理后台路由 - 更严格的安全策略
            route("admin_route") {
                path("/admin/**")
                uri("http://admin.example.org")
                filters {
                    secureHeaders { config ->
                        config.frameOptions = "DENY"
                        config.contentSecurityPolicy = "default-src 'self'; script-src 'self'"
                        config.strictTransportSecurity = "max-age=31536000; includeSubDomains; preload"
                    }
                }
            }

            // API 路由 - 适合 API 的安全策略
            route("api_route") {
                path("/api/**")
                uri("http://api.example.org")
                filters {
                    secureHeaders { config ->
                        config.disable = listOf("x-frame-options")
                        config.referrerPolicy = "origin-when-cross-origin"
                        config.contentSecurityPolicy = "default-src 'self' https:"
                    }
                }
            }
        }.build()
    }
}

Permissions-Policy 支持

Spring Cloud Gateway 还支持新的 Permissions-Policy 头部,用于控制浏览器特性的使用权限。

启用 Permissions-Policy

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # 启用权限策略
          enable: permissions-policy
          # 配置地理位置权限
          permissions-policy: 'geolocation=(self "https://example.com")'

路由级别的 Permissions-Policy

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: location_service_route
          uri: http://location.example.org
          predicates:
            - Path=/location/**
          filters:
            - name: SecureHeaders
              args:
                enable: permissions-policy
                # 只允许当前域和指定域使用地理位置API
                permissions-policy: 'geolocation=("https://location.example.org")'

当启用 Permissions-Policy 但未明确配置指令时,会应用一个非常严格的默认策略,禁用大部分浏览器特性。这可能不适合您的具体环境。

默认 Permissions-Policy 值

当启用但未配置时,默认策略会禁用以下特性:

Permissions-Policy: accelerometer=(), ambient-light-sensor=(), autoplay=(),
battery=(), camera=(), cross-origin-isolated=(), display-capture=(),
document-domain=(), encrypted-media=(), execution-while-not-rendered=(),
execution-while-out-of-viewport=(), fullscreen=(), geolocation=(),
gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(),
navigation-override=(), payment=(), picture-in-picture=(),
publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(),
web-share=(), xr-spatial-tracking=()

实际应用示例

电商网站安全配置

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # 允许支付页面嵌入
          frame-options: "SAMEORIGIN"
          # 适合电商的内容安全策略
          content-security-policy: >
            default-src 'self' https:; script-src 'self' https://pay.example.com https://analytics.google.com; img-src 'self' https: data:; style-src 'self' 'unsafe-inline' https:; font-src 'self' https: data:

          # 启用权限策略,允许支付相关API
          enable: permissions-policy
          permissions-policy: >
            geolocation=(self), camera=(), microphone=(), payment=(self "https://pay.example.com")

      routes:
        # 支付页面特殊配置
        - id: payment_route
          uri: http://payment.internal
          predicates:
            - Path=/payment/**
          filters:
            - name: SecureHeaders
              args:
                # 支付页面需要更严格的安全策略
                content-security-policy: >
                  default-src 'self'; script-src 'self' https://pay.example.com; connect-src 'self' https://api.payment.com

                permissions-policy: 'payment=(self "https://pay.example.com")'

API 网关安全配置

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # API 通常不需要框架保护
          disable: x-frame-options,x-download-options
          # 适合 API 的引用策略
          referrer-policy: "origin-when-cross-origin"
          # API 友好的内容安全策略
          content-security-policy: "default-src 'none'"
          # 禁用大部分浏览器特性
          enable: permissions-policy
          permissions-policy: >
            geolocation=(), camera=(), microphone=(), payment=(), usb=()

安全头部详解

1. X-XSS-Protection

2. Content-Security-Policy (CSP)

CSP 是现代 Web 安全的核心,通过声明允许的资源来源来防止各种攻击:

kotlin
// CSP 配置示例
data class CSPConfig(
    val defaultSrc: List<String> = listOf("'self'"),
    val scriptSrc: List<String> = listOf("'self'", "https:"),
    val styleSrc: List<String> = listOf("'self'", "https:", "'unsafe-inline'"),
    val imgSrc: List<String> = listOf("'self'", "https:", "data:"),
    val objectSrc: List<String> = listOf("'none'")
) {
    /**
     * 构建 CSP 头部值
     */
    fun buildHeaderValue(): String {
        return buildString {
            append("default-src ${defaultSrc.joinToString(" ")}; ")
            append("script-src ${scriptSrc.joinToString(" ")}; ")
            append("style-src ${styleSrc.joinToString(" ")}; ")
            append("img-src ${imgSrc.joinToString(" ")}; ")
            append("object-src ${objectSrc.joinToString(" ")}")
        }
    }
}

@Component
class SecurityHeadersCustomizer {

    /**
     * 为不同类型的应用配置不同的 CSP 策略
     */
    fun createCSPForAppType(appType: String): String {
        return when (appType) {
            "admin" -> CSPConfig(
                scriptSrc = listOf("'self'"),
                styleSrc = listOf("'self'"),
                imgSrc = listOf("'self'", "data:")
            ).buildHeaderValue()

            "ecommerce" -> CSPConfig(
                scriptSrc = listOf("'self'", "https://analytics.google.com", "https://pay.example.com"),
                styleSrc = listOf("'self'", "'unsafe-inline'", "https:"),
                imgSrc = listOf("'self'", "https:", "data:")
            ).buildHeaderValue()

            "api" -> "default-src 'none'"

            else -> CSPConfig().buildHeaderValue()
        }
    }
}

最佳实践

1. 渐进式部署

TIP

建议首先在测试环境中启用所有安全头部,观察应用行为,然后逐步调整配置。

yaml
# 开发环境 - 宽松策略
spring:
  profiles: dev
  cloud:
    gateway:
      filter:
        secure-headers:
          content-security-policy: "default-src 'self' 'unsafe-inline' 'unsafe-eval'"

---
# 生产环境 - 严格策略
spring:
  profiles: prod
  cloud:
    gateway:
      filter:
        secure-headers:
          content-security-policy: "default-src 'self'; script-src 'self'"

2. 监控和调试

kotlin
@Component
class SecurityHeadersMonitor {

    private val logger = LoggerFactory.getLogger(SecurityHeadersMonitor::class.java)

    /**
     * 监控 CSP 违规报告
     */
    @EventListener
    fun handleCSPViolation(violation: CSPViolationEvent) {
        logger.warn("CSP Violation detected: ${violation.details}")

        // 可以发送告警或记录到监控系统
        notifySecurityTeam(violation)
    }

    /**
     * 记录安全头部使用情况
     */
    fun logSecurityHeaders(exchange: ServerWebExchange) {
        val headers = exchange.response.headers
        logger.debug("Applied security headers: {}", headers.toSingleValueMap())
    }
}

3. 自定义安全头部过滤器

kotlin
@Component
class CustomSecureHeadersFilter : GlobalFilter, Ordered {

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        return chain.filter(exchange).then(
            Mono.fromRunnable {
                addCustomSecurityHeaders(exchange)
            }
        )
    }

    private fun addCustomSecurityHeaders(exchange: ServerWebExchange) {
        val headers = exchange.response.headers

        // 添加自定义安全头部
        headers.set("X-Powered-By", "") // 隐藏服务器信息
        headers.set("Server", "") // 隐藏服务器版本
        headers.set("X-Request-ID", exchange.request.id) // 添加请求追踪ID

        // 根据请求路径添加特定头部
        when {
            exchange.request.path.value().startsWith("/api/") -> {
                headers.set("Access-Control-Allow-Origin", "*")
                headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
            }
            exchange.request.path.value().startsWith("/admin/") -> {
                headers.set("X-Frame-Options", "DENY")
                headers.set("X-Admin-Access", "true")
            }
        }
    }

    override fun getOrder(): Int = -1 // 在其他过滤器之前执行
}

常见问题与解决方案

1. CSP 策略导致资源加载失败

Details

问题现象浏览器控制台出现 CSP 违规错误,页面样式或脚本无法正常加载。

解决方案:

  1. 检查浏览器开发者工具的 Console 标签页
  2. 根据错误信息调整 CSP 策略
  3. 使用 report-only 模式进行测试
yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          # 先使用 report-only 模式测试
          content-security-policy: "default-src 'self'; report-uri /csp-report"

2. 第三方服务集成问题

Details

问题现象集成第三方支付、分析服务时被 CSP 阻止。

解决方案: 在 CSP 中明确允许第三方域名:

yaml
spring:
  cloud:
    gateway:
      filter:
        secure-headers:
          content-security-policy: >
            default-src 'self'; script-src 'self' https://www.google-analytics.com https://js.stripe.com; connect-src 'self' https://api.stripe.com; frame-src https://checkout.stripe.com

3. 移动端兼容性问题

Details

问题现象某些安全头部在移动端浏览器中表现异常。

解决方案: 根据 User-Agent 动态调整安全策略:

kotlin
@Component
class MobileAwareSecurityFilter : GlobalFilter {

    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        val userAgent = exchange.request.headers.getFirst("User-Agent") ?: ""
        val isMobile = detectMobile(userAgent)

        return chain.filter(exchange).then(
            Mono.fromRunnable {
                if (isMobile) {
                    // 为移动端调整安全策略
                    adjustSecurityHeadersForMobile(exchange)
                }
            }
        )
    }

    private fun detectMobile(userAgent: String): Boolean {
        return userAgent.contains("Mobile", ignoreCase = true) ||
               userAgent.contains("Android", ignoreCase = true) ||
               userAgent.contains("iPhone", ignoreCase = true)
    }
}

总结

SecureHeaders 过滤器工厂是 Spring Cloud Gateway 提供的强大安全工具,它能够:

  • 自动化安全防护:无需手动配置即可获得基本的安全保护
  • 灵活配置:支持全局和路由级别的个性化配置
  • 标准合规:遵循 Web 安全最佳实践和标准
  • 易于维护:集中式的安全策略管理

建议在项目初期就启用 SecureHeaders 过滤器,并根据具体业务需求逐步优化配置。定期 review 和更新安全策略,确保应用始终具有良好的安全防护能力。

通过合理配置 SecureHeaders 过滤器,可以显著提升应用的安全性,防御多种常见的 Web 攻击,为用户提供更安全的服务体验。