Skip to content

Commit 43a4b46

Browse files
committed
CSP: adjust configuration to use JS files from CDN on prod.
Addressed to #226
1 parent c4b0ebe commit 43a4b46

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

src/main/java/ru/mystamps/web/support/spring/security/ContentSecurityPolicyHeaderWriter.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222

2323
import org.springframework.security.web.header.HeaderWriter;
2424

25+
import lombok.RequiredArgsConstructor;
26+
2527
import ru.mystamps.web.Url;
2628

2729
/**
2830
* Implementation of {@link HeaderWriter} that is adding CSP header depending on the current URL.
2931
*/
32+
@RequiredArgsConstructor
3033
class ContentSecurityPolicyHeaderWriter implements HeaderWriter {
3134

3235
private static final String COLLECTION_INFO_PAGE_PATTERN =
@@ -71,14 +74,22 @@ class ContentSecurityPolicyHeaderWriter implements HeaderWriter {
7174
" 'sha256-biLFinpqYMtWHmXfkA1BPeCY0/fNt46SAZ+BBk5YUog='"
7275
+ " 'sha256-zQDRfdePzsm4666fPPtpna61v74bryIt2Xu5qx2rn4A='";
7376

74-
// - 'self' is required for our own JS files
7577
// - 'unsafe-inline' is required by jquery.min.js (that is using code inside of
7678
// event handlers. We can't use hashing algorithms because they aren't supported
7779
// for handlers. In future, we should get rid of jQuery or use
7880
// 'unsafe-hashed-attributes' from CSP3. Details:
7981
// https://github.com/jquery/jquery/blob/d71f6a53927ad02d/jquery.js#L1441-L1447
8082
// and https://w3c.github.io/webappsec-csp/#unsafe-hashed-attributes-usage)
81-
private static final String SCRIPT_SRC = "script-src 'self' 'unsafe-inline'";
83+
private static final String SCRIPT_SRC = "script-src 'unsafe-inline'";
84+
85+
// - 'self' is required for our own JS files
86+
private static final String SCRIPTS_SELF = " 'self'";
87+
88+
// - 'https://stamps.filezz.ru' is required for our own JS files
89+
// - 'https://maxcdn.bootstrapcdn.com' is required for bootstrap.min.js
90+
// - 'https://yandex.st' is required for jquery.min.js
91+
private static final String SCRIPTS_CDN =
92+
" https://stamps.filezz.ru https://maxcdn.bootstrapcdn.com https://yandex.st";
8293

8394
// - 'unsafe-eval' is required by loader.js from Google Charts
8495
// - 'https://www.gstatic.com' is required by Google Charts
@@ -99,13 +110,15 @@ class ContentSecurityPolicyHeaderWriter implements HeaderWriter {
99110
// number of separators between directives
100111
+ 5;
101112

113+
private final boolean useSingleHost;
114+
102115
@Override
103116
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
104117
String uri = request.getRequestURI();
105118
response.setHeader("Content-Security-Policy-Report-Only", constructDirectives(uri));
106119
}
107120

108-
private static String constructDirectives(String uri) {
121+
private String constructDirectives(String uri) {
109122
boolean onCollectionInfoPage = uri.startsWith(COLLECTION_INFO_PAGE_PATTERN);
110123

111124
StringBuilder sb = new StringBuilder(MIN_HEADER_LENGTH);
@@ -127,7 +140,8 @@ private static String constructDirectives(String uri) {
127140
}
128141

129142
sb.append(SEPARATOR)
130-
.append(SCRIPT_SRC);
143+
.append(SCRIPT_SRC)
144+
.append(useSingleHost ? SCRIPTS_SELF : SCRIPTS_CDN);
131145

132146
if (onCollectionInfoPage) {
133147
sb.append(SCRIPT_COLLECTION_INFO);

src/main/java/ru/mystamps/web/support/spring/security/SecurityConfig.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.context.ApplicationListener;
2727
import org.springframework.context.MessageSource;
2828
import org.springframework.context.annotation.Bean;
29+
import org.springframework.core.env.Environment;
2930
import org.springframework.http.HttpMethod;
3031

3132
import org.springframework.boot.web.filter.OrderedRequestContextFilter;
@@ -60,6 +61,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
6061
@Autowired
6162
private ServicesConfig servicesConfig;
6263

64+
@Autowired
65+
private Environment environment;
66+
6367
@Override
6468
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
6569
public void configure(WebSecurity web) throws Exception {
@@ -69,6 +73,8 @@ public void configure(WebSecurity web) throws Exception {
6973
@Override
7074
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
7175
protected void configure(HttpSecurity http) throws Exception {
76+
boolean useSingleHost = !environment.acceptsProfiles("prod");
77+
7278
http
7379
.authorizeRequests()
7480
.mvcMatchers(Url.ADD_CATEGORY_PAGE).hasAuthority(StringAuthority.CREATE_CATEGORY)
@@ -117,7 +123,7 @@ protected void configure(HttpSecurity http) throws Exception {
117123
.disable()
118124
.headers()
119125
.defaultsDisabled() // TODO
120-
.addHeaderWriter(new ContentSecurityPolicyHeaderWriter());
126+
.addHeaderWriter(new ContentSecurityPolicyHeaderWriter(useSingleHost));
121127
}
122128

123129
// Used in ServicesConfig.getUserService()

0 commit comments

Comments
 (0)