Skip to content
This repository was archived by the owner on Feb 26, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
package io.securecodebox.scanprocesses.amassnmap;

public enum AdditionalTargetAttributes {
NMAP_CONFIGURATION_PROFILE
NMAP_CONFIGURATION_PROFILE,
NMAP_HTTP_HEADERS
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package io.securecodebox.scanprocesses.amassnmap;

import io.securecodebox.model.execution.ScanProcessExecution;
import io.securecodebox.model.execution.ScanProcessExecutionFactory;
import io.securecodebox.model.findings.Finding;
import io.securecodebox.model.findings.Severity;
import io.securecodebox.scanprocesses.amassnmap.util.HttpHeaderStrategy;
import io.securecodebox.scanprocesses.amassnmap.util.HttpHeaders;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;


@Component
public class FilterHttpSecurityHeaders implements JavaDelegate {

private static final Logger LOG = LoggerFactory.getLogger(FilterHttpSecurityHeaders.class);

@Autowired
ScanProcessExecutionFactory processExecutionFactory;


private static final HttpHeaderStrategy[] httpStrategies = new HttpHeaderStrategy[] {
requireHttpServersToRedirectToHttps()
};

private static final HttpHeaderStrategy[] httpsStrategies = new HttpHeaderStrategy[] {
requireStrictTransportSecurityHeader(),
requireContentSecurityPolicyHeader(),
requirePermittedCrossDomainPolicies(),
requireFrameOptionsToBeDenied(),
requireXssProtectionToBeEnabled(),
requireContentTypeOptionsToEqualNosniff()
};


@Override
public void execute(DelegateExecution delegateExecution) throws Exception {
final ScanProcessExecution process = processExecutionFactory.get(delegateExecution);
final ArrayList<Finding> findings = new ArrayList<>();
final long tStart = System.currentTimeMillis();
process.getFindings().stream()
.forEach(finding -> {
if (HttpHeaders.headersPresentInFinding(finding)) {
final HttpHeaders headers = HttpHeaders.fromFinding(finding);
findings.addAll(applyStrategies (headers, finding));
} else {
findings.add(finding);
}
});
final long tStrategiesApplied = System.currentTimeMillis();
final int numberOfAdditionalFindings = findings.size() - process.getFindings().size();
clearFindings(process);
findings.forEach(changedFinding -> process.appendFinding(changedFinding));
LOG.debug("http-headers strategies yielded {} additional findings; finding them took {}ms, storing them {}ms", numberOfAdditionalFindings, tStrategiesApplied - tStart, System.currentTimeMillis() - tStrategiesApplied);
}

private ArrayList<Finding> applyStrategies(HttpHeaders headers, Finding finding) {
final ArrayList<Finding> changedFindings = new ArrayList<>();
changedFindings.add(finding);

final String name = finding.getName();

if (name.equals("http")) {
for (HttpHeaderStrategy httpStrategy : httpStrategies) {
changedFindings.addAll(httpStrategy.apply(headers, finding));
}
} else if (name.equals("https")) {
for (HttpHeaderStrategy httpsStrategy : httpsStrategies) {
changedFindings.addAll(httpsStrategy.apply(headers, finding));
}
}

return changedFindings;
}


private static HttpHeaderStrategy requireHttpServersToRedirectToHttps() {
return new HttpHeaderStrategy("Location")
.ifPresent()
.modifyFinding((value, finding) -> {
finding.setSeverity(Severity.INFORMATIONAL);
finding.setName(finding.getName() + " with redirect to " + value);
finding.setDescription(finding.getDescription() + " with redirect to " + value);
})
.ifMissing()
.createFinding(Severity.HIGH, "missing redirect to https");
}

private static HttpHeaderStrategy requireStrictTransportSecurityHeader() {
return new HttpHeaderStrategy("Strict-Transport-Security")
.ifMissingCreateFinding(Severity.MEDIUM);
}

private static HttpHeaderStrategy requireContentSecurityPolicyHeader() {
return new HttpHeaderStrategy("Content-Security-Policy")
.ifMissingCreateFinding(Severity.MEDIUM);
}

private static HttpHeaderStrategy requirePermittedCrossDomainPolicies() {
return new HttpHeaderStrategy("X-Permitted-Cross-Domain-Policies")
.ifMissingCreateFinding(Severity.MEDIUM);
}

private static HttpHeaderStrategy requireFrameOptionsToBeDenied() {
return new HttpHeaderStrategy("X-Frame-Options")
.ifMissing()
.createFinding(Severity.MEDIUM, "X-Frame-Options header missing")
.ifTrue(value -> !value.toLowerCase().contains("deny"))
.createFinding(Severity.MEDIUM, "X-Frame-Options header misconfigured", value -> "X-Frame-Options should be 'deny', instead it is set to '" + value + "'");
}

private static HttpHeaderStrategy requireXssProtectionToBeEnabled() {
return new HttpHeaderStrategy("X-XSS-Protection")
.ifMissing()
.createFinding(Severity.LOW, "X-XSS-Protection header missing")
.ifTrue(value -> value.startsWith("0"))
.createFinding(Severity.LOW, "X-XSS-Protection manually disabled");
}

private static HttpHeaderStrategy requireContentTypeOptionsToEqualNosniff() {
return new HttpHeaderStrategy("X-Content-Type-Options")
.ifMissing()
.createFinding(Severity.LOW, "X-Content-Type-Options header missing")
.ifTrue(value -> !value.equalsIgnoreCase("nosniff"))
.createFinding(Severity.LOW, "X-Content-Type-Options misconfigured", value -> "X-Conntent-Type-Options should be set to 'nosniff' instead of '" + value + "'");
}


private void clearFindings(ScanProcessExecution process) {
if (!process.getFindings().isEmpty()) {
LOG.debug("Clearing findings. The process had {}", process.getFindings().size());
process.clearFindings();
}
}


private static final HttpHeaderStrategy requireHeader (final String header, final Severity severity) {
return new HttpHeaderStrategy(header)
.ifMissing()
.createFinding(severity, header + " header missing");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@

public enum NmapConfigProfile {
HTTP_PORTS("-Pn -p 80,8080,443,8443"),
TOP_100_PORTS("-Pn --top-ports 100");

HTTP_PORTS_WITH_HTTP_HEADERS("-Pn -p 80,8080,443,8443 --script=http-headers"),
TOP_100_PORTS("-Pn --top-ports 100"),
TOP_100_PORTS_WITH_HTTP_HEADERS("-Pn --top-ports 100 --script=http-headers");
private final String parameter;

NmapConfigProfile(final String parameter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ public void execute(DelegateExecution execution) throws Exception {
originalTargetRestorer.storeOriginalTargetInSeparateProcessVariable(originalTarget, execution);

String nmapProfile = (String) originalTarget.getAttributes().get(AdditionalTargetAttributes.NMAP_CONFIGURATION_PROFILE.name());
String nmapParameters = getNmapParameters(nmapProfile);
Boolean nmapHttpHeaders = (Boolean) originalTarget.getAttributes().get(AdditionalTargetAttributes.NMAP_HTTP_HEADERS.name());
if (nmapHttpHeaders == null) nmapHttpHeaders = false;
String nmapParameters = getNmapParameters(nmapProfile, nmapHttpHeaders);


List<Target> newTargets = new ArrayList<>();
for (Finding finding : findings) {
Expand All @@ -81,6 +84,7 @@ public void execute(DelegateExecution execution) throws Exception {
execution.setVariable(DefaultFields.PROCESS_TARGETS.name(), objectValue);

execution.setVariable("NMAP_CONFIGURATION_TYPE","default");
execution.setVariable("PARSE_HTTP_HEADERS", nmapHttpHeaders);

LOG.debug("Finished TransformAmassResultsToNmapInput Service Task. Continue with nmap scan");

Expand All @@ -89,18 +93,27 @@ public void execute(DelegateExecution execution) throws Exception {
}
}

private String getNmapParameters(String nmapProfile) {
String defaultNmapParameters = NmapConfigProfile.HTTP_PORTS.getParameter();
private String getNmapParameters(String nmapProfile, boolean withHttpHeaders) {
String defaultNmapParameters = (withHttpHeaders ? NmapConfigProfile.HTTP_PORTS_WITH_HTTP_HEADERS : NmapConfigProfile.HTTP_PORTS).getParameter();

if(nmapProfile == null) {
LOG.info("No nmap profile set for combined amass-nmap test. Use http ports as default");
return defaultNmapParameters;
}

switch (NmapConfigProfile.valueOf(nmapProfile)) {
case HTTP_PORTS:
return NmapConfigProfile.HTTP_PORTS.getParameter();
if (withHttpHeaders) {
return NmapConfigProfile.HTTP_PORTS_WITH_HTTP_HEADERS.getParameter();
} else {
return NmapConfigProfile.HTTP_PORTS.getParameter();
}
case TOP_100_PORTS:
return NmapConfigProfile.TOP_100_PORTS.getParameter();
if (withHttpHeaders) {
return NmapConfigProfile.TOP_100_PORTS_WITH_HTTP_HEADERS.getParameter();
} else {
return NmapConfigProfile.TOP_100_PORTS.getParameter();
}
default:
LOG.info("Invalid nmap profile set for combined amass-nmap test. Use http ports as default");
return defaultNmapParameters;
Expand Down
Loading