Skip to content

Commit

Permalink
Merge pull request #3329 from pf-msi/issue-6655-webcachedeception-per…
Browse files Browse the repository at this point in the history
…formance

ascanrulesAlpha: Improve rule performance by not calculating Levenshtein distance above the threshold
  • Loading branch information
kingthorin committed Feb 10, 2022
2 parents 3c18073 + 75e1597 commit 0838a47
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 7 deletions.
3 changes: 3 additions & 0 deletions addOns/ascanrulesAlpha/CHANGELOG.md
Expand Up @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Out-of-band XSS Scan Rule.
- Exponential Entity Expansion (Billion Laughs Attack) Scan Rule.

### Changed
- Improved performance of a Web Cache Deception scan rule (Issue 6655).

## [35] - 2022-01-07
### Fixed
- Log4Shell: Fixed the RMI Payloads (Issue 7002).
Expand Down
Expand Up @@ -120,8 +120,11 @@ public void scan() {
}

private boolean checkSimilarity(String a, String b) {
LevenshteinDistance distance = new LevenshteinDistance();
LevenshteinDistance distance = new LevenshteinDistance(LEVENSHTEIN_THRESHOLD);
int levenshteinDistance = distance.apply(a, b);
if (levenshteinDistance == -1) {
return false; // LEVENSHTEIN_THRESHOLD exceeded
}
// if response length is less than threshold
if (b.length() <= LEVENSHTEIN_THRESHOLD) {
return levenshteinDistance < (int) (b.length() * 0.90);
Expand Down
Expand Up @@ -28,9 +28,12 @@

import fi.iki.elonen.NanoHTTPD;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.parosproxy.paros.core.scanner.Alert;
import org.parosproxy.paros.network.HttpMessage;
import org.parosproxy.paros.network.HttpRequestHeader;
Expand All @@ -39,9 +42,20 @@

class WebCacheDeceptionScanRuleUnitTest extends ActiveScannerTest<WebCacheDeceptionScanRule> {

private static final String RESPONSE_BODY =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mattis ex ac orci consectetur viverra. Aenean porttitor tincidunt ligula. Suspendisse et ornare justo. Fusce vel maximus est. Donec id arcu nec justo egestas hendrerit. Sed pulvinar ultrices ultricies. Mauris ultrices odio non tellus mattis, id pharetra justo porta. Donec venenatis ante ac nisi blandit gravida. Nunc tellus dolor, finibus nec placerat ac, ullamcorper sit amet tellus.";

private static final String AUTHORISED_RESPONSE =
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
+ "<html><head></head><body>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mattis ex ac orci consectetur viverra. Aenean porttitor tincidunt ligula. Suspendisse et ornare justo. Fusce vel maximus est. Donec id arcu nec justo egestas hendrerit. Sed pulvinar ultrices ultricies. Mauris ultrices odio non tellus mattis, id pharetra justo porta. Donec venenatis ante ac nisi blandit gravida. Nunc tellus dolor, finibus nec placerat ac, ullamcorper sit amet tellus.</body></html>";
String.format(
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
+ "<html><head></head><body>%s</body></html>",
RESPONSE_BODY);

private static final String LONG_AUTHORISED_RESPONSE =
String.format(
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
+ "<html><head></head><body>%s</body></html>",
StringUtils.repeat(RESPONSE_BODY, 100));

private static final String UNAUTHORISED_RESPONSE =
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
Expand Down Expand Up @@ -77,7 +91,7 @@ void shouldAlertIfResponseGetsCached() throws Exception {
void shouldNotAlertIfInitialAuthorisedAndUnauthorisedResponseSame() throws Exception {
// Given
HttpMessage message = this.getHttpMessage("/private");
nano.addHandler(new FirstInitialTestResponse("/private"));
nano.addHandler(new FirstInitialTestResponse("/private", AUTHORISED_RESPONSE));
rule.init(message, this.parent);
// When
rule.scan();
Expand Down Expand Up @@ -144,6 +158,20 @@ void shouldReturnExpectedMappings() {
is(equalTo(CommonAlertTag.WSTG_V42_ATHN_06_CACHE_WEAKNESS.getValue())));
}

@Test
@Timeout(value = 3, unit = TimeUnit.SECONDS)
void shouldDetectSimilarMessagesWithoutDelayOnLongResponse() throws Exception {
// Given
HttpMessage message = this.getHttpMessage("/private");
nano.addHandler(new FirstInitialTestResponse("/private", LONG_AUTHORISED_RESPONSE));
rule.init(message, this.parent);
// When
rule.scan();
// Then
assertThat(alertsRaised, hasSize(0));
assertEquals(1, httpMessagesSent.size());
}

private static class CachedTestResponse extends NanoServerHandler {

private final String header;
Expand Down Expand Up @@ -194,14 +222,16 @@ protected NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {

private static class FirstInitialTestResponse extends NanoServerHandler {

FirstInitialTestResponse(String path) {
private final String body;

FirstInitialTestResponse(String path, String body) {
super(path);
this.body = body;
}

@Override
protected NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
return newFixedLengthResponse(
NanoHTTPD.Response.Status.OK, "text/html", AUTHORISED_RESPONSE);
return newFixedLengthResponse(NanoHTTPD.Response.Status.OK, "text/html", this.body);
}
}

Expand Down

0 comments on commit 0838a47

Please sign in to comment.