testing out CSP

This commit is contained in:
Jake Potrebic 2020-12-20 18:20:03 -08:00
parent 62f3a76011
commit e2ac4f8c4a
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
8 changed files with 26 additions and 27 deletions

View File

@ -16,13 +16,12 @@ import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceUrlProvider;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class HangarController {
@ -37,6 +36,8 @@ public abstract class HangarController {
@Autowired
private ObjectMapper mapper;
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
@Autowired
private ResourceUrlProvider resourceUrlProvider;
@ -44,8 +45,6 @@ public abstract class HangarController {
@Autowired
protected Supplier<Optional<UsersTable>> currentUser;
private static final Pattern NONCE_PATTERN = Pattern.compile("(?<=nonce-)[a-zA-Z0-9]+");
protected ModelAndView fillModel(ModelAndView mav) {
// helpers
BeansWrapperBuilder builder = new BeansWrapperBuilder(Configuration.VERSION_2_3_30);
@ -73,12 +72,7 @@ public abstract class HangarController {
mav.addObject("cu", currentUser.get().orElse(null));
mav.addObject("headerData", userService.getHeaderData());
if (response.containsHeader("Content-Security-Policy")) {
Matcher nonceMatcher = NONCE_PATTERN.matcher(response.getHeader("Content-Security-Policy"));
if (!nonceMatcher.find()) {
throw new IllegalStateException("Must have script nonce defined");
}
String nonce = nonceMatcher.group();
mav.addObject("nonce", nonce);
mav.addObject("nonce", request.getAttribute("nonce"));
} else {
mav.addObject("nonce", "missing-csp-header");
}

View File

@ -12,14 +12,15 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.NetworkInterface;
@Component
public class ContentSecurityPolicyFilter extends OncePerRequestFilter {
public final HangarConfig hangarConfig;
private static final String CSP = "default-src 'self' {additional-uris} fonts.googleapis.com; style-src fonts.googleapis.com 'self' {additional-uris} 'unsafe-inline'; font-src fonts.gstatic.com; script-src {additional-uris} 'self' 'nonce-{nonce}' 'unsafe-eval'; img-src 'self' papermc.io paper.readthedocs.io {additional-uris} {auth-uri}; manifest-src {manifest-uri}; prefetch-src {prefetch-uri}; media {prefetch-uri}; object-src 'none'; block-all-mixed-content; frame-ancestors 'none'; base-uri 'none'";
// TODO check this
private static final String CSP = "default-src 'self' {additional-uris} fonts.googleapis.com; style-src fonts.googleapis.com 'self' {additional-uris} 'unsafe-inline'; font-src fonts.gstatic.com; script-src {additional-uris} 'self' 'nonce-{nonce}' 'unsafe-eval'; img-src 'self' data: papermc.io paper.readthedocs.io {additional-uris} {auth-uri}; manifest-src {manifest-uri}; prefetch-src {prefetch-uri}; media-src {prefetch-uri}; object-src 'none'; block-all-mixed-content; frame-ancestors 'none'; base-uri 'none'";
@Autowired
public ContentSecurityPolicyFilter(HangarConfig hangarConfig) {
@ -29,15 +30,19 @@ public class ContentSecurityPolicyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
String CSP_NONCE = RandomStringUtils.randomAlphanumeric(64);
// response.addHeader(
// "Content-Security-Policy",
// CSP
// .replace("{additional-uris}", hangarConfig.isUseWebpack() ? "http://localhost:8081" : "")
// .replace("{auth-uri}", hangarConfig.getAuthUrl())
// .replace("{manifest-uri}", hangarConfig.isUseWebpack() ? "http://localhost:8081/manifest/manifest.json" : "'self'")
// .replace("{prefetch-uri}", hangarConfig.isUseWebpack() ? "http://localhost:8081" : "'self'")
// .replace("{nonce}", CSP_NONCE));
// TODO still some changes to make to the header
NetworkInterface.networkInterfaces().forEach(networkInterface -> {
System.out.println(networkInterface.getName());
System.out.println(networkInterface.getInterfaceAddresses());
});
response.addHeader(
"Content-Security-Policy",
CSP
.replace("{additional-uris}", hangarConfig.isUseWebpack() ? "http://localhost:8081 http://*:8081 ws://*:8081" : "") // TODO idk how to get the local IP to put here... without those last two entries, there are a bunch of console errors. Maybe you can figure it out Mini.
.replace("{auth-uri}", hangarConfig.getAuthUrl())
.replace("{manifest-uri}", hangarConfig.isUseWebpack() ? "http://localhost:8081/manifest/manifest.json" : "'self'")
.replace("{prefetch-uri}", hangarConfig.isUseWebpack() ? "http://localhost:8081" : "'self'")
.replace("{nonce}", CSP_NONCE));
request.setAttribute("nonce", CSP_NONCE);
filterChain.doFilter(request, response);
}
}

View File

@ -51,7 +51,7 @@ showFooter: Boolean = true, noContainer: Boolean = false, additionalMeta: Html =
<meta name="theme-color" content="#2980B9">
<#-- google foo -->
<script async src="https://www.googletagmanager.com/gtag/js?id=${config.gaCode}"></script>
<script async nonce="${nonce}" src="https://www.googletagmanager.com/gtag/js?id=${config.gaCode}"></script>
<script nonce="${nonce}">
<#outputformat "JavaScript">
window.dataLayer = window.dataLayer || [];

View File

@ -3,7 +3,7 @@
<#import "*/layout/base.ftlh" as base />
<#assign scriptsVar>
<script nonce="${nonce}" type="text/javascript" src="${hangar.url("js/showNotes.js")}"></script>
<script type="text/javascript" src="${hangar.url("js/showNotes.js")}"></script>
<script nonce="${nonce}">
<#outputformat "JavaScript">
window.resourcePath = '${project.ownerName}/${project.slug}'

View File

@ -26,7 +26,7 @@ Documentation page within Project overview.
window.CAN_MANAGE_MEMBERS = ${sp.permissions.has(Permission.ManageSubjectMembers)?c};
</#outputformat>
</script>
<script nonce="${nonce}" type="text/javascript" src="${hangar.url("js/project-view.js")}"></script>
<script type="text/javascript" src="${hangar.url("js/project-view.js")}"></script>
</#assign>
<#assign styleVar>

View File

@ -22,7 +22,7 @@ Base template for Project overview.
window.CAN_EDIT_PAGES = ${sp.perms(Permission.EditPage)?c};
</#outputformat>
</script>
<script nonce="${nonce}" type="text/javascript" src="${hangar.url("ext/js/admonition.js")}"></script>
<script type="text/javascript" src="${hangar.url("ext/js/admonition.js")}"></script>
<script type="text/javascript" src="${hangar.url("js/project-controls.js")}"></script>
${additionalScripts}
</#assign>

View File

@ -13,7 +13,7 @@
</#if>
</#outputformat>
</script>
<script nonce="${nonce}" type="text/javascript" src="${hangar.url("js/version-reviews.js")}"></script>
<script type="text/javascript" src="${hangar.url("js/version-reviews.js")}"></script>
</#assign>
<#assign ReviewState=@helper["io.papermc.hangar.model.generated.ReviewState"] />

View File

@ -19,7 +19,7 @@
};
</#outputformat>
</script>
<script nonce="${nonce}" type="text/javascript" src="${hangar.url("js/stats.js")}"></script>
<script type="text/javascript" src="${hangar.url("js/stats.js")}"></script>
</#assign>
<@base.base title="Stats" additionalScripts=scriptsVar>