Skip to content

Commit

Permalink
Merge pull request #5667 from psiinon/pscan/polyfill-speed
Browse files Browse the repository at this point in the history
Pscanrules: Fixed polyfill rule running slowly
  • Loading branch information
thc202 authored Aug 27, 2024
2 parents e686c02 + 73bc791 commit 34772fe
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 27 deletions.
2 changes: 2 additions & 0 deletions addOns/pscanrules/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Clarified Missing Anti-clickjacking Header description.
- Depend on Passive Scanner add-on to include it by default (Issue 7959).
- Re-examine Cache-control Directives scan rule now ignores cache-control for POST method requests (Issue 8592).
### Fixed
- Polyfill scan rule running slowly.

## [59] - 2024-07-24
### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.zaproxy.zap.extension.pscanrules;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -45,26 +46,39 @@ public class PolyfillCdnScriptScanRule extends PluginPassiveScanner

private static final int PLUGIN_ID = 10115;

private static Pattern POLYFILL_IO =
Pattern.compile("http[s]?://.*polyfill\\.io/.*", Pattern.CASE_INSENSITIVE);
private static Pattern BOOTCSS_COM =
Pattern.compile("http[s]?://.*bootcss\\.com/.*", Pattern.CASE_INSENSITIVE);
private static Pattern BOOTCDN_NET =
Pattern.compile("http[s]?://.*bootcdn\\.net/.*", Pattern.CASE_INSENSITIVE);
private static Pattern STATICFILE_NET =
Pattern.compile("http[s]?://.*staticfile\\.net/.*", Pattern.CASE_INSENSITIVE);
private static Pattern STATICFILE_ORG =
Pattern.compile("http[s]?://.*staticfile\\.org/.*", Pattern.CASE_INSENSITIVE);
private static Pattern UNIONADJS_COM =
Pattern.compile("http[s]?://.*unionadjs\\.com/.*", Pattern.CASE_INSENSITIVE);
private static Pattern XHSBPZA_COM =
Pattern.compile("http[s]?://.*xhsbpza\\.com/.*", Pattern.CASE_INSENSITIVE);
private static Pattern UNION_MACOMS_LA =
Pattern.compile("http[s]?://.*union\\.macoms\\.la/.*", Pattern.CASE_INSENSITIVE);
private static Pattern NEWCRBPC_COM =
Pattern.compile("http[s]?://.*newcrbpc\\.com/.*", Pattern.CASE_INSENSITIVE);

private static Pattern[] ALL_DOMAINS = {
private static final String START_P = "http[s]?://.*";
private static final String END_P = ".*\\w";

private static final String POLYFILL_IO = "polyfill.io/";
private static final String BOOTCSS_COM = "bootcss.com/";
private static final String BOOTCDN_NET = "bootcdn.net/";
private static final String STATICFILE_NET = "staticfile.net/";
private static final String STATICFILE_ORG = "staticfile.org/";
private static final String UNIONADJS_COM = "unionadjs.com/";
private static final String XHSBPZA_COM = "xhsbpza.com/";
private static final String UNION_MACOMS_LA = "union.macoms.la/";
private static final String NEWCRBPC_COM = "newcrbpc.com/";

private static final Pattern POLYFILL_IO_URL =
Pattern.compile(START_P + POLYFILL_IO + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern BOOTCSS_COM_URL =
Pattern.compile(START_P + BOOTCSS_COM + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern BOOTCDN_NET_URL =
Pattern.compile(START_P + BOOTCDN_NET + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern STATICFILE_NET_URL =
Pattern.compile(START_P + STATICFILE_NET + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern STATICFILE_ORG_URL =
Pattern.compile(START_P + STATICFILE_ORG + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern UNIONADJS_COM_URL =
Pattern.compile(START_P + UNIONADJS_COM + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern XHSBPZA_COM_URL =
Pattern.compile(START_P + XHSBPZA_COM + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern UNION_MACOMS_LA_URL =
Pattern.compile(START_P + UNION_MACOMS_LA + END_P, Pattern.CASE_INSENSITIVE);
private static final Pattern NEWCRBPC_COM_URL =
Pattern.compile(START_P + NEWCRBPC_COM + END_P, Pattern.CASE_INSENSITIVE);

private static final String[] ALL_DOMAINS = {
POLYFILL_IO,
BOOTCSS_COM,
BOOTCDN_NET,
Expand All @@ -76,6 +90,18 @@ public class PolyfillCdnScriptScanRule extends PluginPassiveScanner
NEWCRBPC_COM
};

private static final Pattern[] ALL_DOMAIN_URLS = {
POLYFILL_IO_URL,
BOOTCSS_COM_URL,
BOOTCDN_NET_URL,
STATICFILE_NET_URL,
STATICFILE_ORG_URL,
UNIONADJS_COM_URL,
XHSBPZA_COM_URL,
UNION_MACOMS_LA_URL,
NEWCRBPC_COM_URL
};

@Override
public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
if (msg.getResponseBody().length() > 0 && msg.getResponseHeader().isHtml()) {
Expand All @@ -85,7 +111,7 @@ public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
for (Element sourceElement : sourceElements) {
String src = sourceElement.getAttributeValue("src");
if (src != null) {
for (Pattern pattern : ALL_DOMAINS) {
for (Pattern pattern : ALL_DOMAIN_URLS) {
if (pattern.matcher(src).matches()) {
this.createHighConfidenceAlert(src, sourceElement.toString())
.raise();
Expand All @@ -101,12 +127,18 @@ public void scanHttpResponseReceive(HttpMessage msg, int id, Source source) {
// Check the script contents, in case they are loading scripts via JS
for (Element sourceElement : sourceElements) {
String contents = sourceElement.getContent().toString();

for (Pattern pattern : ALL_DOMAINS) {
Matcher matcher = pattern.matcher(contents);
if (matcher.find()) {
this.createLowConfidenceAlert(null, matcher.group(0)).raise();
break;
String contentsLc = contents.toLowerCase(Locale.ROOT);

for (int i = 0; i < ALL_DOMAINS.length; i++) {
String domain = ALL_DOMAINS[i];
// Use "contains" first as it makes a huge difference in speed
if (contentsLc.contains(domain)) {
Pattern pattern = ALL_DOMAIN_URLS[i];
Matcher matcher = pattern.matcher(contents);
if (matcher.find()) {
this.createLowConfidenceAlert(null, matcher.group(0)).raise();
break;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -267,4 +268,25 @@ void polyfillScriptInScriptBody(String domain) throws HttpMalformedHeaderExcepti
assertThat(alertsRaised.get(0).getEvidence(), equalTo(domain + "/v3/polyfill.min.js"));
assertThat(alertsRaised.get(0).getConfidence(), equalTo(1));
}

@Test
void shouldRunQuickly() throws Exception {

HttpMessage msg = new HttpMessage();
msg.setRequestHeader("GET https://www.bbc.com/ HTTP/1.1");
msg.setResponseBody(this.getHtml("bbc.html"));
msg.setResponseHeader(
"HTTP/1.1 200 OK\r\n"
+ "Server: Apache-Coyote/1.1\r\n"
+ "Content-Type: text/html;charset=ISO-8859-1\r\n"
+ "Content-Length: "
+ msg.getResponseBody().length()
+ "\r\n");
long start = System.currentTimeMillis();
scanHttpResponseReceive(msg);
long end = System.currentTimeMillis();

assertThat(alertsRaised.size(), equalTo(0));
assertThat(end - start, lessThan(200L));
}
}
Loading

0 comments on commit 34772fe

Please sign in to comment.