Appearance
SecureHeaders GatewayFilter Factory
概述
SecureHeaders 过滤器工厂是 Spring Cloud Gateway 提供的一个重要安全组件,它会在 HTTP 响应中自动添加多个安全头部,帮助防御常见的 Web 安全威胁。这些安全头部遵循了业界最佳实践,能够有效提升应用的安全性。
业务场景与问题解决
在现代 Web 应用中,安全问题日益突出。以下是 SecureHeaders 过滤器解决的典型安全问题:
1. XSS 攻击防护
恶意用户可能注入 JavaScript 代码,窃取用户信息或执行恶意操作。
2. 内容类型嗅探攻击
浏览器可能错误地解释文件类型,导致安全漏洞。
3. 点击劫持攻击
恶意网站通过 iframe 嵌入目标网站,欺骗用户点击。
4. 中间人攻击
在不安全的网络环境中,攻击者可能截获或篡改通信内容。
默认安全头部
SecureHeaders 过滤器默认添加以下安全头部:
具体头部说明
| 安全头部 | 默认值 | 作用 |
|---|---|---|
X-XSS-Protection | 1 (mode=block) | 启用浏览器内置的 XSS 过滤器 |
Strict-Transport-Security | max-age=631138519 | 强制使用 HTTPS 连接 |
X-Frame-Options | DENY | 禁止页面被嵌入到 frame 中 |
X-Content-Type-Options | nosniff | 防止浏览器进行 MIME 类型嗅探 |
Referrer-Policy | no-referrer | 不发送引用页面信息 |
Content-Security-Policy | 详见下方 | 定义内容安全策略 |
X-Download-Options | noopen | 防止 IE 自动打开下载文件 |
X-Permitted-Cross-Domain-Policies | none | 禁止跨域策略文件 |
默认的 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 违规错误,页面样式或脚本无法正常加载。
解决方案:
- 检查浏览器开发者工具的 Console 标签页
- 根据错误信息调整 CSP 策略
- 使用
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.com3. 移动端兼容性问题
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 攻击,为用户提供更安全的服务体验。