diff --git a/docker/CHANGELOG.md b/docker/CHANGELOG.md index 6fdeba6746e..79fafc566d8 100644 --- a/docker/CHANGELOG.md +++ b/docker/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All notable changes to the docker containers will be documented in this file. +### 2025-10-31 +- Added config options for recording which packaged scan is being run. + ### 2025-03-25 - Update ZAP API scan to support host override for local OpenAPI spec. diff --git a/docker/zap-api-scan.py b/docker/zap-api-scan.py index 9face73517b..acf0a52f95b 100755 --- a/docker/zap-api-scan.py +++ b/docker/zap-api-scan.py @@ -344,7 +344,7 @@ def main(argv): if running_in_docker(): try: - params = [] + params = ['-config', 'stats.pkg.apiscan-api=1'] if "-silent" not in zap_options: params.append('-addonupdate') @@ -368,7 +368,7 @@ def main(argv): if context_file: mount_dir = os.path.dirname(os.path.abspath(context_file)) - params = [] + params = ['-config', 'stats.pkg.apiscan-api=1'] if "-silent" not in zap_options: params.append('-addonupdate') diff --git a/docker/zap-baseline.py b/docker/zap-baseline.py index c3def39ccb5..73f92f569d8 100755 --- a/docker/zap-baseline.py +++ b/docker/zap-baseline.py @@ -179,6 +179,7 @@ def main(argv): use_af = True af_supported = True af_override = False + no_af_reason = '' pass_count = 0 warn_count = 0 @@ -211,6 +212,7 @@ def main(argv): elif opt == '-g': generate = arg af_supported = False + no_af_reason = 'gen' elif opt == '-d': logging.getLogger().setLevel(logging.DEBUG) debug = True @@ -221,12 +223,15 @@ def main(argv): elif opt == '-D': delay = int(arg) af_supported = False + no_af_reason = 'delay' elif opt == '-n': context_file = arg af_supported = False + no_af_reason = 'context' elif opt == '-p': progress_file = arg af_supported = False + no_af_reason = 'progress' elif opt == '-r': report_html = arg elif opt == '-J': @@ -240,6 +245,7 @@ def main(argv): elif opt == '-i': info_unspecified = True af_supported = False + no_af_reason = 'info' elif opt == '-I': ignore_warn = True elif opt == '-j': @@ -252,6 +258,7 @@ def main(argv): usage() sys.exit(3) af_supported = False + no_af_reason = 'level' elif opt == '-z': zap_options = arg elif opt == '-s': @@ -261,14 +268,17 @@ def main(argv): elif opt == '-U': user = arg af_supported = False + no_af_reason = 'user' elif opt == '--hook': hook_file = arg af_supported = False + no_af_reason = 'hook' elif opt == '--auto': use_af = True af_override = True elif opt == '--autooff': use_af = False + no_af_reason = 'optout' check_zap_client_version() @@ -415,7 +425,7 @@ def main(argv): run_zap_inline(port, install_opts) # Run ZAP inline with the yaml file - params = ['-autorun', yaml_file] + params = ['-autorun', yaml_file, '-config', 'stats.pkg.baseline-af=1'] add_zap_options(params, zap_options) @@ -457,7 +467,10 @@ def main(argv): else: try: - params = ['-config', 'spider.maxDuration=' + str(mins)] + params = ['-config', 'spider.maxDuration=' + str(mins), '-config', 'stats.pkg.baseline-api=1'] + + if len(no_af_reason) > 0: + params.extend(['-config', 'stats.pkg.xbaseline-' + no_af_reason + '=1']) if "-silent" not in zap_options: params.append('-addonupdate') @@ -482,7 +495,7 @@ def main(argv): mount_dir = os.path.dirname(os.path.abspath(context_file)) - params = ['-config', 'spider.maxDuration=' + str(mins)] + params = ['-config', 'spider.maxDuration=' + str(mins), '-config', 'stats.pkg.baseline-api=1'] if "-silent" not in zap_options: params.append('-addonupdate') diff --git a/docker/zap-full-scan.py b/docker/zap-full-scan.py index 2d2fe68acea..d27f303d45c 100755 --- a/docker/zap-full-scan.py +++ b/docker/zap-full-scan.py @@ -281,7 +281,7 @@ def main(argv): if running_in_docker(): try: - params = ['-config', 'spider.maxDuration=' + str(mins)] + params = ['-config', 'spider.maxDuration=' + str(mins), '-config', 'stats.pkg.fullscan-api=1'] if "-silent" not in zap_options: params.append('-addonupdate') @@ -307,7 +307,7 @@ def main(argv): if context_file: mount_dir = os.path.dirname(os.path.abspath(context_file)) - params = ['-config', 'spider.maxDuration=' + str(mins)] + params = ['-config', 'spider.maxDuration=' + str(mins), '-config', 'stats.pkg.fullscan-api=1'] if "-silent" not in zap_options: params.append('-addonupdate') diff --git a/docker/zap-webswing.sh b/docker/zap-webswing.sh index 1401f60594a..14e82355dbf 100755 --- a/docker/zap-webswing.sh +++ b/docker/zap-webswing.sh @@ -66,7 +66,7 @@ case "$1" in cd $HOME # Set up the ZAP runtime options - ZAP_OPTS="-host 0.0.0.0 -port 8090" + ZAP_OPTS="-host 0.0.0.0 -port 8090 -config stats.pkg.webswing=1" ZAP_PUBLIC="/zap/wrk/zap_root_ca.cer" ZAP_PRIVATE="/zap/wrk/zap_root_ca.key" diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/Alert.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/Alert.java index d0fd1914e6a..86a85f46937 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/Alert.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/Alert.java @@ -70,6 +70,7 @@ // ZAP: 2023/11/14 When setting CWE also add a CWE alert tag with an appropriate URL. // ZAP: 2025/10/01 Added support for nodeName. // ZAP: 2025/10/16 Added support for systemic alerts. +// ZAP: 2025/10/30 Adjust compateTo and equals handling of nodeName and uri (now case sensitive) package org.parosproxy.paros.core.scanner; import java.net.URL; @@ -488,9 +489,9 @@ public int compareTo(Alert alert2) { } if (StringUtils.isNotBlank(nodeName) && StringUtils.isNotBlank(alert2.nodeName)) { - result = nodeName.compareToIgnoreCase(alert2.nodeName); + result = nodeName.compareTo(alert2.nodeName); } else { - result = uri.compareToIgnoreCase(alert2.uri); + result = uri.compareTo(alert2.uri); } if (result != 0) { return result; @@ -570,7 +571,7 @@ public boolean equals(Object obj) { if (!nodeName.equals(item.nodeName)) { return false; } - } else if (!uri.equalsIgnoreCase(item.uri)) { + } else if (!uri.equals(item.uri)) { return false; } if (!param.equalsIgnoreCase(item.param)) { diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java index d8433a3dfd7..f7f5de99081 100644 --- a/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java +++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/Scanner.java @@ -99,6 +99,7 @@ public class Scanner implements Runnable { public static final String ASCAN_SCAN_STARTED_STATS = "stats.ascan.started"; + public static final String ASCAN_SCAN_STARTED_USER_STATS = "stats.ascan.started.user"; public static final String ASCAN_SCAN_STOPPED_STATS = "stats.ascan.stopped"; public static final String ASCAN_SCAN_TIME_STATS = "stats.ascan.time"; public static final String ASCAN_URLS_STATS = "stats.ascan.urls"; @@ -209,6 +210,9 @@ public void start(Target target) { ActiveScanEventPublisher.publishScanEvent( ScanEventPublisher.SCAN_STARTED_EVENT, this.getId(), target, this.user); Stats.incCounter(ASCAN_SCAN_STARTED_STATS); + if (this.user != null) { + Stats.incCounter(ASCAN_SCAN_STARTED_USER_STATS); + } } public void stop() { diff --git a/zap/src/test/java/org/parosproxy/paros/core/scanner/AlertUnitTest.java b/zap/src/test/java/org/parosproxy/paros/core/scanner/AlertUnitTest.java index 97dfefa7610..162f10e632a 100644 --- a/zap/src/test/java/org/parosproxy/paros/core/scanner/AlertUnitTest.java +++ b/zap/src/test/java/org/parosproxy/paros/core/scanner/AlertUnitTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -150,6 +151,36 @@ void shouldNotEqualIfAlertRefDifferent() { assertThat(equals, is(equalTo(false))); } + @Test + void shouldNotEqualIfAlertUriDifferentCapitalization() { + // Given + Alert alertA = new Alert(1); + Alert alertB = new Alert(1); + // When + alertA.setAlertId(0); + alertB.setAlertId(1); + alertA.setUri("https://example.com/SCRIPT?q=a"); + alertB.setUri("https://example.com/script?q=a"); + boolean equals = alertA.equals(alertB); + // Then + assertThat(equals, is(equalTo(false))); + } + + @Test + void shouldNotEqualIfAlertNodeNameDifferentCapitalization() { + // Given + Alert alertA = new Alert(1); + Alert alertB = new Alert(1); + // When + alertA.setAlertId(0); + alertB.setAlertId(1); + alertA.setNodeName("https://example.com/SCRIPT (q)"); + alertB.setNodeName("https://example.com/script (q)"); + boolean equals = alertA.equals(alertB); + // Then + assertThat(equals, is(equalTo(false))); + } + @Test void shouldNotCompareIfAlertRefDifferent() { // Given @@ -165,6 +196,36 @@ void shouldNotCompareIfAlertRefDifferent() { assertThat(cmp, is(equalTo(-1))); } + @Test + void shouldCompareDissimilarIfAlertNodeNameDifferentByCapitalization() { + // Given + Alert alertA = new Alert(1); + Alert alertB = new Alert(1); + // When + alertA.setAlertId(0); + alertB.setAlertId(1); + alertA.setNodeName("https://example.com/SCRIPT (q)"); + alertB.setNodeName("https://example.com/script (q)"); + int cmp = alertA.compareTo(alertB); + // Then + assertThat(cmp, is(lessThan(0))); + } + + @Test + void shouldCompareDissimilarIfAlertUriDifferentByCapitalization() { + // Given + Alert alertA = new Alert(1); + Alert alertB = new Alert(1); + // When + alertA.setAlertId(0); + alertB.setAlertId(1); + alertA.setUri("https://example.com/SCRIPT?q=a"); + alertB.setUri("https://example.com/script?q=a"); + int cmp = alertA.compareTo(alertB); + // Then + assertThat(cmp, is(lessThan(0))); + } + @Test void shouldBuildAlertWithOneTag() { // Given @@ -289,7 +350,6 @@ void shouldAddLastCweTagEvenIfCweIdSetTwiceAndBuildTwice() { // Then Map tags = alert.getTags(); assertThat(tagCount, is(equalTo(1))); - System.out.println(tags); assertThat(tags.containsKey(cwe2Key), is(equalTo(true))); assertThat(tags.get(cwe2Key), is(equalTo(cwe2Url))); } diff --git a/zap/src/test/java/org/zaproxy/zap/extension/alert/AlertSetUnitTest.java b/zap/src/test/java/org/zaproxy/zap/extension/alert/AlertSetUnitTest.java index b56c2a057fe..cc17ea085a3 100644 --- a/zap/src/test/java/org/zaproxy/zap/extension/alert/AlertSetUnitTest.java +++ b/zap/src/test/java/org/zaproxy/zap/extension/alert/AlertSetUnitTest.java @@ -157,20 +157,20 @@ void shouldFindSimilarAlert() { getAlert( 0, "Test Alert", - "https://www.example.com/(test)", + "https://www.example.com/ (test)", "https://www.example.com/?test=1"); Alert a2 = getAlert( 1, "Test Alert", - "https://www.example.com/(test)", + "https://www.example.com/ (test)", "https://www.example.com/?test=2"); Alert a3 = getAlert( 2, "Test Alert", - "https://www.example.com/(x)", - "https://www.example.com/?test=2"); + "https://www.example.com/ (x)", + "https://www.example.com/?x=2"); // When alertSet.add(a1);