Skip to content

Commit 5ffc2c8

Browse files
committed
Enable a strong enforce CSP by default (#6670)
1 parent 6cb3c15 commit 5ffc2c8

3 files changed

Lines changed: 76 additions & 10 deletions

File tree

api/src/org/labkey/api/settings/OptionalFeatureStartupListener.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
import org.apache.commons.lang3.BooleanUtils;
55
import org.labkey.api.module.ModuleLoader;
66
import org.labkey.api.settings.AdminConsole.OptionalFeatureFlag;
7+
import org.labkey.api.util.DOM;
78
import org.labkey.api.util.StartupListener;
89

910
import java.util.Comparator;
1011
import java.util.Map;
1112

1213
import static org.labkey.api.settings.AppProps.SCOPE_OPTIONAL_FEATURE;
14+
import static org.labkey.api.util.DOM.SPAN;
15+
import static org.labkey.api.util.DOM.STRONG;
1316

1417
public class OptionalFeatureStartupListener implements StartupListener
1518
{
@@ -38,6 +41,12 @@ public OptionalFeatureStartupPropertyHandler()
3841
);
3942
}
4043

44+
@Override
45+
public DOM.Renderable getScopeDescription()
46+
{
47+
return SPAN(STRONG(getScope()), " - set these properties to true/false to enable/disable the corresponding feature flag");
48+
}
49+
4150
@Override
4251
public void handle(Map<OptionalFeatureFlag, StartupPropertyEntry> properties)
4352
{

api/src/org/labkey/filters/ContentSecurityPolicyFilter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
public class ContentSecurityPolicyFilter implements Filter
4747
{
4848
public static final String FEATURE_FLAG_DISABLE_ENFORCE_CSP = "disableEnforceCsp";
49+
public static final String FEATURE_FLAG_FORWARD_CSP_REPORTS = "forwardCspReports";
4950

5051
private static final String NONCE_SUBST = "REQUEST.SCRIPT.NONCE";
5152
private static final String REPORT_PARAMETER_SUBSTITUTION = "CSP.REPORT.PARAMS";

core/src/org/labkey/core/admin/AdminController.java

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,15 @@
359359
import java.net.URI;
360360
import java.net.URISyntaxException;
361361
import java.net.URL;
362+
import java.net.http.HttpClient;
363+
import java.net.http.HttpRequest;
364+
import java.net.http.HttpResponse;
362365
import java.nio.file.Files;
363366
import java.nio.file.Path;
364367
import java.nio.file.Paths;
365368
import java.sql.SQLException;
366369
import java.text.DecimalFormat;
370+
import java.time.Duration;
367371
import java.util.ArrayList;
368372
import java.util.Arrays;
369373
import java.util.Collection;
@@ -11960,6 +11964,13 @@ public void addNavTrail(NavTree root)
1196011964
}
1196111965
}
1196211966

11967+
private static final URI LABKEY_ORG_REPORT_ACTION;
11968+
11969+
static
11970+
{
11971+
LABKEY_ORG_REPORT_ACTION = URI.create("https://www.labkey.org/admin-contentSecurityPolicyReport.api");
11972+
}
11973+
1196311974
@RequiresNoPermission
1196411975
@CSRF(CSRF.Method.NONE)
1196511976
public static class ContentSecurityPolicyReportAction extends ReadOnlyApiAction<SimpleApiJsonForm>
@@ -11995,19 +12006,64 @@ public Object execute(SimpleApiJsonForm form, BindException errors) throws Excep
1199512006
String urlString = cspReport.optString("document-uri", null);
1199612007
if (urlString != null)
1199712008
{
11998-
String path = new URLHelper(urlString).deleteParameters().getPath();
12009+
String path = new URLHelper(urlString).deleteParameters().getURIString();
1199912010
if (null == reports.put(path, Boolean.TRUE) || _log.isDebugEnabled())
1200012011
{
12001-
if (isNotBlank(userAgent))
12002-
jsonObj.put("user-agent", userAgent);
12003-
String labkeyVersion = request.getParameter("labkeyVersion");
12004-
if (null != labkeyVersion)
12005-
jsonObj.put("labkeyVersion", labkeyVersion);
12006-
String cspVersion = request.getParameter("cspVersion");
12007-
if (null != cspVersion)
12008-
jsonObj.put("cspVersion", cspVersion);
12012+
// Don't modify forwarded reports; they already have user, ip, user-agent, etc. from the forwarding server.
12013+
boolean forwarded = jsonObj.optBoolean("forwarded", false);
12014+
if (!forwarded)
12015+
{
12016+
jsonObj.put("user", getUser().getEmail());
12017+
String ipAddress = request.getHeader("X-FORWARDED-FOR");
12018+
if (ipAddress == null)
12019+
ipAddress = request.getRemoteAddr();
12020+
jsonObj.put("ip", ipAddress);
12021+
if (isNotBlank(userAgent))
12022+
jsonObj.put("user-agent", userAgent);
12023+
String labkeyVersion = request.getParameter("labkeyVersion");
12024+
if (null != labkeyVersion)
12025+
jsonObj.put("labkeyVersion", labkeyVersion);
12026+
String cspVersion = request.getParameter("cspVersion");
12027+
if (null != cspVersion)
12028+
jsonObj.put("cspVersion", cspVersion);
12029+
}
12030+
1200912031
var jsonStr = jsonObj.toString(2);
12010-
_log.warn("ContentSecurityPolicy warning on page: " + urlString + "\n" + jsonStr);
12032+
_log.warn("ContentSecurityPolicy warning on page: {}\n{}", urlString, jsonStr);
12033+
12034+
if (!forwarded && OptionalFeatureService.get().isFeatureEnabled(ContentSecurityPolicyFilter.FEATURE_FLAG_FORWARD_CSP_REPORTS))
12035+
{
12036+
jsonObj.put("forwarded", true);
12037+
12038+
// Create an HttpClient
12039+
HttpClient client = HttpClient.newBuilder()
12040+
.connectTimeout(Duration.ofSeconds(10))
12041+
.build();
12042+
12043+
// Create the POST request
12044+
HttpRequest remoteRequest = HttpRequest.newBuilder()
12045+
.uri(LABKEY_ORG_REPORT_ACTION)
12046+
.header("Content-Type", request.getContentType()) // Use whatever the browser set
12047+
.POST(HttpRequest.BodyPublishers.ofString(jsonObj.toString(2)))
12048+
.build();
12049+
12050+
// Send the request and get the response
12051+
HttpResponse<String> response = client.send(remoteRequest, HttpResponse.BodyHandlers.ofString());
12052+
12053+
if (response.statusCode() != 200)
12054+
{
12055+
_log.error("ContentSecurityPolicy report forwarding to https://www.labkey.org failed: {}\n{}", response.statusCode(), response.body());
12056+
}
12057+
else
12058+
{
12059+
JSONObject jsonResponse = new JSONObject(response.body());
12060+
boolean success = jsonResponse.optBoolean("success", false);
12061+
if (!success)
12062+
{
12063+
_log.error("ContentSecurityPolicy report forwarding to https://www.labkey.org failed: {}", jsonResponse);
12064+
}
12065+
}
12066+
}
1201112067
}
1201212068
}
1201312069
}

0 commit comments

Comments
 (0)