Spring Security Config : HttpSecurity安全配置器 HeadersConfigurer

概述

介绍

作为一个配置HttpSecuritySecurityConfigurer,HeadersConfigurer的配置任务如下 :

  • 配置如下安全过滤器Filter
    • HeaderWriterFilter

HeadersConfigurer自己内置定义了一组特定头部的配置类并允许使用者配置,这些配置类每个其实对应一个相应的头部写入器HeaderWriter。除此之外,HeadersConfigurer也允许开发者提供自定义的头部写入器HeaderWriter

HeadersConfigurer自己内置的特定头部的配置类如下 :

配置类 对应头部写入器 对应头部
CacheControlConfig CacheControlHeadersWriter Expires,Pragma,Cache-Control
ContentSecurityPolicyConfig ContentSecurityPolicyHeaderWriter Content-Security-Policy,Content-Security-Policy-Report-Only
ContentTypeOptionsConfig XContentTypeOptionsHeaderWriter X-Content-Type-Options
FeaturePolicyConfig FeaturePolicyHeaderWriter Feature-Policy
FrameOptionsConfig XFrameOptionsHeaderWriter X-Frame-Options
HpkpConfig HpkpHeaderWriter Public-Key-Pins,Public-Key-Pins-Report-Only
HstsConfig HstsHeaderWriter Strict-Transport-Security
ReferrerPolicyConfig ReferrerPolicyHeaderWriter Referrer-Policy
XXssConfig XXssProtectionHeaderWriter X-XSS-Protection

HeadersConfigurer通过如下方法允许开发人员添加自定义头部写入器 :

  • addHeaderWriter(HeaderWriter headerWriter)

应用HeadersConfigurer而不做任何自定义的缺省情况下,它所产生的HeaderWriterFilter会往响应写入如下头部信息 :

 Cache-Control: no-cache, no-store, max-age=0, must-revalidate
 Pragma: no-cache
 Expires: 0
 X-Content-Type-Options: nosniff
 Strict-Transport-Security: max-age=31536000 ; includeSubDomains
 X-Frame-Options: DENY
 X-XSS-Protection: 1; mode=block

继承关系

Spring Security Config : HttpSecurity安全配置器 HeadersConfigurer_第1张图片

使用

    // HttpSecurity 代码片段
	public HeadersConfigurer<HttpSecurity> headers() throws Exception {
		return getOrApply(new HeadersConfigurer<>());
	}

源代码

源代码版本 Spring Security Config 5.1.4.RELEASE

package org.springframework.security.config.annotation.web.configurers;

// 省略 imports

public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
		AbstractHttpConfigurer<HeadersConfigurer<H>, H> {
	private List<HeaderWriter> headerWriters = new ArrayList<>();

	// --- default header writers ---

	private final ContentTypeOptionsConfig contentTypeOptions = new ContentTypeOptionsConfig();

	private final XXssConfig xssProtection = new XXssConfig();

	private final CacheControlConfig cacheControl = new CacheControlConfig();

	private final HstsConfig hsts = new HstsConfig();

	private final FrameOptionsConfig frameOptions = new FrameOptionsConfig();

	private final HpkpConfig hpkp = new HpkpConfig();

	private final ContentSecurityPolicyConfig contentSecurityPolicy = 
			new ContentSecurityPolicyConfig();

	private final ReferrerPolicyConfig referrerPolicy = new ReferrerPolicyConfig();

	private final FeaturePolicyConfig featurePolicy = new FeaturePolicyConfig();

	/**
	 * Creates a new instance
	 *
	 * @see HttpSecurity#headers()
	 */
	public HeadersConfigurer() {
	}

	/**
	 * Adds a {@link HeaderWriter} instance
	 *
	 * @param headerWriter the {@link HeaderWriter} instance to add
	 * @return the {@link HeadersConfigurer} for additional customizations
	 */
	public HeadersConfigurer<H> addHeaderWriter(HeaderWriter headerWriter) {
		Assert.notNull(headerWriter, "headerWriter cannot be null");
		this.headerWriters.add(headerWriter);
		return this;
	}

	/**
	 * Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the X-Content-Type-Options:
	 *
	 * 
	 * X-Content-Type-Options: nosniff
	 * 
* * @return the ContentTypeOptionsConfig for additional customizations */
public ContentTypeOptionsConfig contentTypeOptions() { return contentTypeOptions.enable(); } public final class ContentTypeOptionsConfig { private XContentTypeOptionsHeaderWriter writer; private ContentTypeOptionsConfig() { enable(); } /** * Removes the X-XSS-Protection header. * * @return {@link HeadersConfigurer} for additional customization. */ public HeadersConfigurer<H> disable() { writer = null; return and(); } /** * Allows customizing the {@link HeadersConfigurer} * @return the {@link HeadersConfigurer} for additional customization */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Ensures that Content Type Options is enabled * * @return the {@link ContentTypeOptionsConfig} for additional customization */ private ContentTypeOptionsConfig enable() { if (writer == null) { writer = new XContentTypeOptionsHeaderWriter(); } return this; } } /** * Note this is not comprehensive XSS protection! * * * Allows customizing the XXssProtectionHeaderWriter which adds the X-XSS-Protection header * * * @return the HeadersConfigurer for additional customizations */ public XXssConfig xssProtection() { return xssProtection.enable(); } public final class XXssConfig { private XXssProtectionHeaderWriter writer; private XXssConfig() { enable(); } /** * If false, will not specify the mode as blocked. In this instance, any content * will be attempted to be fixed. If true, the content will be replaced with "#". * * @param enabled the new value */ public XXssConfig block(boolean enabled) { writer.setBlock(enabled); return this; } /** * If true, the header value will contain a value of 1. For example: * *
		 * X-XSS-Protection: 1
		 * 
* * or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given * XXssProtectionHeaderWriter is true * * *
		 * X-XSS-Protection: 1; mode=block
		 * 
* * If false, will explicitly disable specify that X-XSS-Protection is disabled. * For example: * *
		 * X-XSS-Protection: 0
		 * 
* * @param enabled the new value */
public XXssConfig xssProtectionEnabled(boolean enabled) { writer.setEnabled(enabled); return this; } /** * Disables X-XSS-Protection header (does not include it) * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> disable() { writer = null; return and(); } /** * Allows completing configuration of X-XSS-Protection and continuing * configuration of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Ensures the X-XSS-Protection header is enabled if it is not already. * * @return the {@link XXssConfig} for additional customization */ private XXssConfig enable() { if (writer == null) { writer = new XXssProtectionHeaderWriter(); } return this; } } /** * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the * following headers: *
    *
  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
  • *
  • Pragma: no-cache
  • *
  • Expires: 0
  • *
* * @return the {@link HeadersConfigurer} for additional customizations */
public CacheControlConfig cacheControl() { return cacheControl.enable(); } public final class CacheControlConfig { private CacheControlHeadersWriter writer; private CacheControlConfig() { enable(); } /** * Disables Cache Control * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> disable() { writer = null; return HeadersConfigurer.this; } /** * Allows completing configuration of Cache Control and continuing * configuration of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Ensures the Cache Control headers are enabled if they are not already. * * @return the {@link CacheControlConfig} for additional customization */ private CacheControlConfig enable() { if (writer == null) { writer = new CacheControlHeadersWriter(); } return this; } } /** * Allows customizing the {@link HstsHeaderWriter} which provides support for HTTP Strict Transport Security * (HSTS). * * @return the {@link HeadersConfigurer} for additional customizations */ public HstsConfig httpStrictTransportSecurity() { return hsts.enable(); } public final class HstsConfig { private HstsHeaderWriter writer; private HstsConfig() { enable(); } /** *

* Sets the value (in seconds) for the max-age directive of the * Strict-Transport-Security header. The default is one year. *

* *

* This instructs browsers how long to remember to keep this domain as a known * HSTS Host. See Section 6.1.1 for * additional details. *

* * @param maxAgeInSeconds the maximum amount of time (in seconds) to consider this * domain as a known HSTS Host. * @throws IllegalArgumentException if maxAgeInSeconds is negative */
public HstsConfig maxAgeInSeconds(long maxAgeInSeconds) { writer.setMaxAgeInSeconds(maxAgeInSeconds); return this; } /** * Sets the {@link RequestMatcher} used to determine if the * "Strict-Transport-Security" should be added. If true the header is added, else * the header is not added. By default the header is added when * {@link HttpServletRequest#isSecure()} returns true. * * @param requestMatcher the {@link RequestMatcher} to use. * @throws IllegalArgumentException if {@link RequestMatcher} is null */ public HstsConfig requestMatcher(RequestMatcher requestMatcher) { writer.setRequestMatcher(requestMatcher); return this; } /** *

* If true, subdomains should be considered HSTS Hosts too. The default is true. *

* *

* See Section * 6.1.2 for additional details. *

* * @param includeSubDomains true to include subdomains, else false */
public HstsConfig includeSubDomains(boolean includeSubDomains) { writer.setIncludeSubDomains(includeSubDomains); return this; } /** * Disables Strict Transport Security * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> disable() { writer = null; return HeadersConfigurer.this; } /** * Allows completing configuration of Strict Transport Security and continuing * configuration of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Ensures that Strict-Transport-Security is enabled if it is not already * * @return the {@link HstsConfig} for additional customization */ private HstsConfig enable() { if (writer == null) { writer = new HstsHeaderWriter(); } return this; } } /** * Allows customizing the {@link XFrameOptionsHeaderWriter}. * * @return the {@link HeadersConfigurer} for additional customizations */ public FrameOptionsConfig frameOptions() { return frameOptions.enable(); } public final class FrameOptionsConfig { private XFrameOptionsHeaderWriter writer; private FrameOptionsConfig() { enable(); } /** * Specify to DENY framing any content from this application. * * @return the {@link HeadersConfigurer} for additional customization. */ public HeadersConfigurer<H> deny() { writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY); return and(); } /** *

* Specify to allow any request that comes from the same origin to frame this * application. For example, if the application was hosted on example.com, then * example.com could frame the application, but evil.com could not frame the * application. *

* * @return the {@link HeadersConfigurer} for additional customization. */
public HeadersConfigurer<H> sameOrigin() { writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN); return and(); } /** * Prevents the header from being added to the response. * * @return the {@link HeadersConfigurer} for additional configuration. */ public HeadersConfigurer<H> disable() { writer = null; return and(); } /** * Allows continuing customizing the headers configuration. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Enables FrameOptionsConfig if it is not already enabled. * * @return the FrameOptionsConfig for additional customization. */ private FrameOptionsConfig enable() { if (writer == null) { writer = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY); } return this; } } /** * Allows customizing the {@link HpkpHeaderWriter} which provides support for HTTP Public Key Pinning (HPKP). * * @return the {@link HeadersConfigurer} for additional customizations * * @since 4.1 */ public HpkpConfig httpPublicKeyPinning() { return hpkp.enable(); } public final class HpkpConfig { private HpkpHeaderWriter writer; private HpkpConfig() {} /** *

* Sets the value for the pin- directive of the Public-Key-Pins header. *

* *

* The pin directive specifies a way for web host operators to indicate * a cryptographic identity that should be bound to a given web host. * See Section 2.1.1 * for additional details. *

* * @param pins the map of base64-encoded SPKI fingerprint & cryptographic * hash algorithm pairs. * @throws IllegalArgumentException if pins is null */
public HpkpConfig withPins(Map<String, String> pins) { writer.setPins(pins); return this; } /** *

* Adds a list of SHA256 hashed pins for the pin- directive of the Public-Key-Pins header. *

* *

* The pin directive specifies a way for web host operators to indicate * a cryptographic identity that should be bound to a given web host. * See Section 2.1.1 * for additional details. *

* * @param pins a list of base64-encoded SPKI fingerprints. * @throws IllegalArgumentException if a pin is null */
public HpkpConfig addSha256Pins(String ... pins) { writer.addSha256Pins(pins); return this; } /** *

* Sets the value (in seconds) for the max-age directive of the Public-Key-Pins header. * The default is 60 days. *

* *

* This instructs browsers how long they should regard the host (from whom the * message was received) * as a known pinned host. See * Section 2.1.2 * for additional details. *

* * @param maxAgeInSeconds the maximum amount of time (in seconds) to regard the host * as a known pinned host. * @throws IllegalArgumentException if maxAgeInSeconds is negative */
public HpkpConfig maxAgeInSeconds(long maxAgeInSeconds) { writer.setMaxAgeInSeconds(maxAgeInSeconds); return this; } /** *

* If true, the pinning policy applies to this pinned host as well as any subdomains * of the host's domain name. The default is false. *

* *

* See Section 2.1.3 * for additional details. *

* * @param includeSubDomains true to include subdomains, else false */
public HpkpConfig includeSubDomains(boolean includeSubDomains) { writer.setIncludeSubDomains(includeSubDomains); return this; } /** *

* If true, the browser should not terminate the connection with the server. * The default is true. *

* *

* See Section 2.1 * for additional details. *

* * @param reportOnly true to report only, else false */
public HpkpConfig reportOnly(boolean reportOnly) { writer.setReportOnly(reportOnly); return this; } /** *

* Sets the URI to which the browser should report pin validation failures. *

* *

* See Section 2.1.4 * for additional details. *

* * @param reportUri the URI where the browser should send the report to. */
public HpkpConfig reportUri(URI reportUri) { writer.setReportUri(reportUri); return this; } /** *

* Sets the URI to which the browser should report pin validation failures. *

* *

* See Section 2.1.4 * for additional details. *

* * @param reportUri the URI where the browser should send the report to. * @throws IllegalArgumentException if the reportUri is not a valid URI */
public HpkpConfig reportUri(String reportUri) { writer.setReportUri(reportUri); return this; } /** * Prevents the header from being added to the response. * * @return the {@link HeadersConfigurer} for additional configuration. */ public HeadersConfigurer<H> disable() { writer = null; return and(); } /** * Allows completing configuration of Public Key Pinning and continuing * configuration of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } /** * Ensures that Public-Key-Pins or Public-Key-Pins-Report-Only is enabled * if it is not already * * @return the {@link HstsConfig} for additional customization */ private HpkpConfig enable() { if (writer == null) { writer = new HpkpHeaderWriter(); } return this; } } /** *

* Allows configuration for Content Security Policy (CSP) * Level 2. *

* *

* Calling this method automatically enables (includes) the Content-Security-Policy header * in the response using the supplied security policy directive(s). *

* *

* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports * the writing of the two headers as detailed in the W3C Candidate Recommendation: *

*
    *
  • Content-Security-Policy
  • *
  • Content-Security-Policy-Report-Only
  • *
* * @see ContentSecurityPolicyHeaderWriter * @since 4.1 * @return the ContentSecurityPolicyConfig for additional configuration * @throws IllegalArgumentException if policyDirectives is null or empty */
public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) { this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives); return contentSecurityPolicy; } public final class ContentSecurityPolicyConfig { private ContentSecurityPolicyHeaderWriter writer; private ContentSecurityPolicyConfig() { } /** * Enables (includes) the Content-Security-Policy-Report-Only header in the response. * * @return the {@link ContentSecurityPolicyConfig} for additional configuration */ public ContentSecurityPolicyConfig reportOnly() { this.writer.setReportOnly(true); return this; } /** * Allows completing configuration of Content Security Policy and continuing * configuration of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } } /** * Clears all of the default headers from the response. After doing so, one can add * headers back. For example, if you only want to use Spring Security's cache control * you can use the following: * *
	 * http.headers().defaultsDisabled().cacheControl();
	 * 
* * @return the {@link HeadersConfigurer} for additional customization */
public HeadersConfigurer<H> defaultsDisabled() { contentTypeOptions.disable(); xssProtection.disable(); cacheControl.disable(); hsts.disable(); frameOptions.disable(); return this; } @Override public void configure(H http) throws Exception { HeaderWriterFilter headersFilter = createHeaderWriterFilter(); http.addFilter(headersFilter); } /** * Creates the {@link HeaderWriter} * * @return the {@link HeaderWriter} */ private HeaderWriterFilter createHeaderWriterFilter() { List<HeaderWriter> writers = getHeaderWriters(); if (writers.isEmpty()) { throw new IllegalStateException( "Headers security is enabled, but no headers will be added. " + " Either add headers or disable headers security"); } HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers); headersFilter = postProcess(headersFilter); return headersFilter; } /** * Gets the {@link HeaderWriter} instances and possibly initializes with the defaults. * * @return */ private List<HeaderWriter> getHeaderWriters() { List<HeaderWriter> writers = new ArrayList<>(); addIfNotNull(writers, contentTypeOptions.writer); addIfNotNull(writers, xssProtection.writer); addIfNotNull(writers, cacheControl.writer); addIfNotNull(writers, hsts.writer); addIfNotNull(writers, frameOptions.writer); addIfNotNull(writers, hpkp.writer); addIfNotNull(writers, contentSecurityPolicy.writer); addIfNotNull(writers, referrerPolicy.writer); addIfNotNull(writers, featurePolicy.writer); writers.addAll(headerWriters); return writers; } private <T> void addIfNotNull(List<T> values, T value) { if (value != null) { values.add(value); } } /** *

* Allows configuration for Referrer Policy. *

* *

* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing * of the header as detailed in the W3C Technical Report: *

*
    *
  • Referrer-Policy
  • *
* *

Default value is:

* *
	 * Referrer-Policy: no-referrer
	 * 
* * @see ReferrerPolicyHeaderWriter * @since 4.2 * @return the ReferrerPolicyConfig for additional configuration */
public ReferrerPolicyConfig referrerPolicy() { this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(); return this.referrerPolicy; } /** *

* Allows configuration for Referrer Policy. *

* *

* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing * of the header as detailed in the W3C Technical Report: *

*
    *
  • Referrer-Policy
  • *
* * @see ReferrerPolicyHeaderWriter * @since 4.2 * @return the ReferrerPolicyConfig for additional configuration * @throws IllegalArgumentException if policy is null or empty */
public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) { this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy); return this.referrerPolicy; } public final class ReferrerPolicyConfig { private ReferrerPolicyHeaderWriter writer; private ReferrerPolicyConfig() { } public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } } /** * Allows configuration for Feature * Policy. *

* Calling this method automatically enables (includes) the {@code Feature-Policy} * header in the response using the supplied policy directive(s). *

* Configuration is provided to the {@link FeaturePolicyHeaderWriter} which is * responsible for writing the header. * * @see FeaturePolicyHeaderWriter * @since 5.1 * @return the {@link FeaturePolicyHeaderWriter} for additional configuration * @throws IllegalArgumentException if policyDirectives is {@code null} or empty */ public FeaturePolicyConfig featurePolicy(String policyDirectives) { this.featurePolicy.writer = new FeaturePolicyHeaderWriter(policyDirectives); return featurePolicy; } public final class FeaturePolicyConfig { private FeaturePolicyHeaderWriter writer; private FeaturePolicyConfig() { } /** * Allows completing configuration of Feature Policy and continuing configuration * of headers. * * @return the {@link HeadersConfigurer} for additional configuration */ public HeadersConfigurer<H> and() { return HeadersConfigurer.this; } } }

参考文章

你可能感兴趣的:(Spring,Security,分析)