1
0
mirror of synced 2026-08-05 17:57:15 +00:00

Add preload support to Strict-Transport-Security

1. Preload support in Servlet Security(XML & Java)
2. Preload support in Reactive Security
3. Test for preload support in Servlet Security
4. Test for preload support in Reactive Security

Fixes: gh-6312
This commit is contained in:
Ankur Pathak
2018-12-21 21:59:54 +05:30
committed by Rob Winch
parent 739594dee8
commit b7ed919cee
13 changed files with 3860 additions and 21 deletions
@@ -30,9 +30,10 @@ import org.springframework.util.Assert;
* Security (HSTS)</a>.
*
* <p>
* By default the expiration is one year and subdomains will be included. This can be
* customized using {@link #setMaxAgeInSeconds(long)} and
* {@link #setIncludeSubDomains(boolean)} respectively.
* By default the expiration is one year, subdomains will be included and preload will not
* be included. This can be customized using {@link #setMaxAgeInSeconds(long)},
* {@link #setIncludeSubDomains(boolean)} and {@link #setPreload(boolean)}
* respectively.
* </p>
*
* <p>
@@ -46,6 +47,11 @@ import org.springframework.util.Assert;
* {@link RequestMatcher}.
* </p>
*
* <p>
* See <a href="https://hstspreload.org/">Website hstspreload.org</a>
* for additional details on HSTS preload.
* </p>
*
* @author Rob Winch
* @since 3.2
*/
@@ -62,8 +68,29 @@ public final class HstsHeaderWriter implements HeaderWriter {
private boolean includeSubDomains;
private boolean preload;
private String hstsHeaderValue;
/**
* Creates a new instance
*
* @param requestMatcher maps to {@link #setRequestMatcher(RequestMatcher)}
* @param maxAgeInSeconds maps to {@link #setMaxAgeInSeconds(long)}
* @param includeSubDomains maps to {@link #setIncludeSubDomains(boolean)}
* @param preload maps to {@link #setPreload(boolean)}
* @since 5.2.0
* @author Ankur Pathak
*/
public HstsHeaderWriter(RequestMatcher requestMatcher, long maxAgeInSeconds,
boolean includeSubDomains, boolean preload) {
this.requestMatcher = requestMatcher;
this.maxAgeInSeconds = maxAgeInSeconds;
this.includeSubDomains = includeSubDomains;
this.preload = preload;
updateHstsHeaderValue();
}
/**
* Creates a new instance
*
@@ -73,10 +100,20 @@ public final class HstsHeaderWriter implements HeaderWriter {
*/
public HstsHeaderWriter(RequestMatcher requestMatcher, long maxAgeInSeconds,
boolean includeSubDomains) {
this.requestMatcher = requestMatcher;
this.maxAgeInSeconds = maxAgeInSeconds;
this.includeSubDomains = includeSubDomains;
updateHstsHeaderValue();
this(requestMatcher, maxAgeInSeconds, includeSubDomains, false);
}
/**
* Creates a new instance
*
* @param maxAgeInSeconds maps to {@link #setMaxAgeInSeconds(long)}
* @param includeSubDomains maps to {@link #setIncludeSubDomains(boolean)}
* @param preload maps to {@link #setPreload(boolean)}
* @since 5.2.0
* @author Ankur Pathak
*/
public HstsHeaderWriter(long maxAgeInSeconds, boolean includeSubDomains, boolean preload) {
this(new SecureRequestMatcher(), maxAgeInSeconds, includeSubDomains, preload);
}
/**
@@ -86,7 +123,7 @@ public final class HstsHeaderWriter implements HeaderWriter {
* @param includeSubDomains maps to {@link #setIncludeSubDomains(boolean)}
*/
public HstsHeaderWriter(long maxAgeInSeconds, boolean includeSubDomains) {
this(new SecureRequestMatcher(), maxAgeInSeconds, includeSubDomains);
this(new SecureRequestMatcher(), maxAgeInSeconds, includeSubDomains, false);
}
/**
@@ -95,7 +132,7 @@ public final class HstsHeaderWriter implements HeaderWriter {
* @param maxAgeInSeconds maps to {@link #setMaxAgeInSeconds(long)}
*/
public HstsHeaderWriter(long maxAgeInSeconds) {
this(new SecureRequestMatcher(), maxAgeInSeconds, true);
this(new SecureRequestMatcher(), maxAgeInSeconds, true, false);
}
/**
@@ -104,7 +141,7 @@ public final class HstsHeaderWriter implements HeaderWriter {
* @param includeSubDomains maps to {@link #setIncludeSubDomains(boolean)}
*/
public HstsHeaderWriter(boolean includeSubDomains) {
this(new SecureRequestMatcher(), DEFAULT_MAX_AGE_SECONDS, includeSubDomains);
this(new SecureRequestMatcher(), DEFAULT_MAX_AGE_SECONDS, includeSubDomains, false);
}
/**
@@ -186,12 +223,33 @@ public final class HstsHeaderWriter implements HeaderWriter {
this.includeSubDomains = includeSubDomains;
updateHstsHeaderValue();
}
/**
* <p>
* If true, preload will be included in HSTS Header. The default is false.
* </p>
*
* <p>
* See <a href="http://tools.ietf.org/html/rfc6797#section-6.1.2">Section 6.1.2</a>
* for additional details.
* </p>
*
* @param preload true to include preload, else false
* @since 5.2.0
* @autor Ankur Pathak
*/
public void setPreload(boolean preload) {
this.preload = preload;
updateHstsHeaderValue();
}
private void updateHstsHeaderValue() {
String headerValue = "max-age=" + this.maxAgeInSeconds;
if (this.includeSubDomains) {
headerValue += " ; includeSubDomains";
}
if (this.preload) {
headerValue += " ; preload";
}
this.hstsHeaderValue = headerValue;
}
@@ -34,6 +34,8 @@ public final class StrictTransportSecurityServerHttpHeadersWriter
private String subdomain;
private String preload;
private ServerHttpHeadersWriter delegate;
/**
@@ -42,6 +44,7 @@ public final class StrictTransportSecurityServerHttpHeadersWriter
public StrictTransportSecurityServerHttpHeadersWriter() {
setIncludeSubDomains(true);
setMaxAge(Duration.ofDays(365L));
setPreload(false);
updateDelegate();
}
@@ -62,6 +65,24 @@ public final class StrictTransportSecurityServerHttpHeadersWriter
updateDelegate();
}
/**
* <p>
* Sets if preload should be included. Default is false
* </p>
*
* <p>
* See <a href="https://hstspreload.org/">Website hstspreload.org</a>
* for additional details.
* </p>
* @param preload if preload should be included
* @since 5.2.0
* @author Ankur Pathak
*/
public void setPreload(boolean preload) {
this.preload = preload ? " ; preload" : "";
updateDelegate();
}
/**
* Sets the max age of the header. Default is a year.
* @param maxAge the max age of the header
@@ -73,7 +94,7 @@ public final class StrictTransportSecurityServerHttpHeadersWriter
private void updateDelegate() {
delegate = StaticServerHttpHeadersWriter.builder()
.header(STRICT_TRANSPORT_SECURITY, maxAge + subdomain)
.header(STRICT_TRANSPORT_SECURITY, maxAge + subdomain + preload)
.build();
}