feat: show directly requested file in requests overview

When a call directly hits a file it is now show up in the requests overview. This helps the user whether an attack from WebGoat actually requested the uploaded file.

Closes: gh-1551
This commit is contained in:
Nanne Baars 2023-12-04 21:34:16 +01:00
parent 3d651526be
commit ae261f201a
3 changed files with 81 additions and 20 deletions

View File

@ -22,8 +22,6 @@
package org.owasp.webgoat.webwolf.requests; package org.owasp.webgoat.webwolf.requests;
import static java.util.stream.Collectors.toList;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant; import java.time.Instant;
@ -67,10 +65,10 @@ public class Requests {
var model = new ModelAndView("requests"); var model = new ModelAndView("requests");
String username = (null != authentication) ? authentication.getName() : "anonymous"; String username = (null != authentication) ? authentication.getName() : "anonymous";
var traces = var traces =
traceRepository.findAllTraces().stream() traceRepository.findAll().stream()
.filter(t -> allowedTrace(t, username)) .filter(t -> allowedTrace(t, username))
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))) .map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t)))
.collect(toList()); .toList();
model.addObject("traces", traces); model.addObject("traces", traces);
return model; return model;
@ -93,7 +91,7 @@ public class Requests {
} }
private String path(HttpExchange t) { private String path(HttpExchange t) {
return (String) t.getRequest().getUri().getPath(); return t.getRequest().getUri().getPath();
} }
private String toJsonString(HttpExchange t) { private String toJsonString(HttpExchange t) {

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.webwolf.requests; package org.owasp.webgoat.webwolf.requests;
import static org.owasp.webgoat.webwolf.requests.WebWolfTraceRepository.Exclusion.contains;
import static org.owasp.webgoat.webwolf.requests.WebWolfTraceRepository.Exclusion.endsWith;
import com.google.common.collect.EvictingQueue; import com.google.common.collect.EvictingQueue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -36,31 +39,50 @@ import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
* @since 8/13/17. * @since 8/13/17.
*/ */
public class WebWolfTraceRepository implements HttpExchangeRepository { public class WebWolfTraceRepository implements HttpExchangeRepository {
private enum MatchingMode {
CONTAINS,
ENDS_WITH,
EQUALS;
}
record Exclusion(String path, MatchingMode mode) {
public boolean matches(String path) {
return switch (mode) {
case CONTAINS -> path.contains(this.path);
case ENDS_WITH -> path.endsWith(this.path);
case EQUALS -> path.equals(this.path);
};
}
public static Exclusion contains(String exclusionPattern) {
return new Exclusion(exclusionPattern, MatchingMode.CONTAINS);
}
public static Exclusion endsWith(String exclusionPattern) {
return new Exclusion(exclusionPattern, MatchingMode.ENDS_WITH);
}
}
private final EvictingQueue<HttpExchange> traces = EvictingQueue.create(10000); private final EvictingQueue<HttpExchange> traces = EvictingQueue.create(10000);
private final List<String> exclusionList = private final List<Exclusion> exclusionList =
List.of( List.of(
"/tmpdir", contains("/tmpdir"),
"/home", contains("/home"),
"/files", endsWith("/files"),
"/images/", contains("/images/"),
"/js/", contains("/js/"),
"/webjars/", contains("/webjars/"),
"/requests", contains("/requests"),
"/css/", contains("/css/"),
"/mail"); contains("/mail"));
@Override @Override
public List<HttpExchange> findAll() { public List<HttpExchange> findAll() {
return List.of();
}
public List<HttpExchange> findAllTraces() {
return new ArrayList<>(traces); return new ArrayList<>(traces);
} }
private boolean isInExclusionList(String path) { private boolean isInExclusionList(String path) {
return exclusionList.stream().anyMatch(e -> path.contains(e)); return exclusionList.stream().anyMatch(e -> e.matches(path));
} }
@Override @Override

View File

@ -0,0 +1,41 @@
package org.owasp.webgoat.webwolf.requests;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.net.URI;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
class WebWolfTraceRepositoryTest {
@Test
@DisplayName("When a user hits a file upload it should be recorded")
void shouldAddFilesRequest() {
HttpExchange httpExchange = mock();
HttpExchange.Request request = mock();
when(httpExchange.getRequest()).thenReturn(request);
when(request.getUri()).thenReturn(URI.create("http://localhost:9090/files/test1234/test.jpg"));
WebWolfTraceRepository repository = new WebWolfTraceRepository();
repository.add(httpExchange);
Assertions.assertThat(repository.findAll()).hasSize(1);
}
@Test
@DisplayName("When a user hits file upload page ('/files') it should be recorded")
void shouldAddNotAddFilesRequestOverview() {
HttpExchange httpExchange = mock();
HttpExchange.Request request = mock();
when(httpExchange.getRequest()).thenReturn(request);
when(request.getUri()).thenReturn(URI.create("http://localhost:9090/files"));
WebWolfTraceRepository repository = new WebWolfTraceRepository();
repository.add(httpExchange);
Assertions.assertThat(repository.findAll()).hasSize(0);
}
}