Spring Security如何配置指定页面允许任意站点iframe嵌入
Spring Security 5.3.x 按页面维度放开iframe嵌入限制实现方案
关于<frame-options>标签ref属性的说明
你查到的ref属性仅在policy="ALLOW-FROM"模式下生效,引用的Bean需要实现org.springframework.security.web.header.writers.frameoptions.AllowFromStrategy接口,接口定义如下:
public interface AllowFromStrategy { /** * 返回值为X-Frame-Options头ALLOW-FROM指令后拼接的允许来源域名 * 返回null时将不输出X-Frame-Options头 */ String getAllowFromValue(HttpServletRequest request); }
注意:X-Frame-Options: ALLOW-FROM 域名是非标准指令,当前主流Chrome、Edge、Safari浏览器均已废弃对该语法的支持,无法实现「允许任意第三方域名嵌入」的需求,不推荐使用该方案。
推荐实现方案(兼容所有浏览器)
核心思路是禁用默认的全局frame-options配置,通过请求匹配器对指定路径单独控制安全头输出:默认路径保持SAMEORIGIN策略,需要放开的路径不输出X-Frame-Options头,可搭配CSP指令做现代浏览器兼容。
1. 调整Spring Security XML配置
先禁用默认的frame-options自动配置,引入自定义的头写入器:
<security:headers> <!-- 禁用默认的全局X-Frame-Options配置 --> <security:frame-options disabled="true"/> <!-- 引入自定义的X-Frame-Options写入逻辑 --> <security:header ref="customXFrameOptionsHeaderWriter"/> <!-- 可选:引入CSP兼容配置 --> <security:header ref="cspFrameAncestorsHeaderWriter"/> <!-- 其余原有安全头配置保持不变,如content-type-options、cache-control等 --> </security:headers>
2. 配置自定义头写入器
你可以选择Java Config或者纯XML配置两种方式:
方式一:Java Config配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.web.header.HeaderWriter; import org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter; import org.springframework.security.web.header.writers.XFrameOptionsHeaderWriter; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsMode; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import java.util.Arrays; import java.util.List; @Configuration public class SecurityHeaderConfig { // 自定义需要放开iframe限制的路径列表 private static final List<String> ALLOW_IFRAME_PATHS = Arrays.asList( "/public/embed/**", "/share/page/**" ); @Bean public HeaderWriter customXFrameOptionsHeaderWriter() { // 构建放开路径的匹配规则 RequestMatcher allowIframeMatcher = new OrRequestMatcher( ALLOW_IFRAME_PATHS.stream() .map(AntPathRequestMatcher::new) .toArray(RequestMatcher[]::new) ); // 非放开路径应用SAMEORIGIN策略 RequestMatcher sameOriginPathMatcher = new NegatedRequestMatcher(allowIframeMatcher); return new DelegatingRequestMatcherHeaderWriter( sameOriginPathMatcher, new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN) ); } // 可选:现代浏览器CSP兼容配置,允许任意来源嵌入放开路径 @Bean public HeaderWriter cspFrameAncestorsHeaderWriter() { RequestMatcher allowIframeMatcher = new OrRequestMatcher( ALLOW_IFRAME_PATHS.stream() .map(AntPathRequestMatcher::new) .toArray(RequestMatcher[]::new) ); return new DelegatingRequestMatcherHeaderWriter( allowIframeMatcher, (request, response) -> response.setHeader( "Content-Security-Policy", "frame-ancestors *;" ) ); } }
方式二:纯XML Bean配置
如果不想使用Java Config,可以直接在XML中声明相关Bean:
<!-- 配置需要放开的路径匹配规则 --> <bean id="allowIframeMatcher" class="org.springframework.security.web.util.matcher.OrRequestMatcher"> <constructor-arg> <list> <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> <constructor-arg value="/public/embed/**"/> </bean> <bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"> <constructor-arg value="/share/page/**"/> </bean> </list> </constructor-arg> </bean> <!-- 配置需要应用SAMEORIGIN的路径规则 --> <bean id="sameOriginPathMatcher" class="org.springframework.security.web.util.matcher.NegatedRequestMatcher"> <constructor-arg ref="allowIframeMatcher"/> </bean> <!-- 配置SAMEORIGIN头写入器 --> <bean id="sameOriginFrameWriter" class="org.springframework.security.web.header.writers.XFrameOptionsHeaderWriter"> <constructor-arg value="SAMEORIGIN"/> </bean> <!-- 自定义X-Frame-Options写入器 --> <bean id="customXFrameOptionsHeaderWriter" class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter"> <constructor-arg ref="sameOriginPathMatcher"/> <constructor-arg ref="sameOriginFrameWriter"/> </bean>
纯XML配置CSP写入器时,自定义一个实现
HeaderWriter接口的简单类完成CSP头写入即可,逻辑和Java Config版本一致。
3. 验证逻辑
服务启动后:
- 访问普通业务页面,响应头存在
X-Frame-Options: SAMEORIGIN,第三方站点无法通过iframe嵌入 - 访问配置的放开路径,响应头无X-Frame-Options字段,配置CSP的场景下会返回
Content-Security-Policy: frame-ancestors *;,可被任意第三方站点正常嵌入
内容的提问来源于stack exchange,提问作者curious1
相关产品推荐
相关产品推荐

