Merge conflicts resolved
This commit is contained in:
@ -28,16 +28,24 @@ import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwt;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
@ -47,10 +55,26 @@ import java.util.List;
|
||||
@AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"})
|
||||
public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
|
||||
|
||||
public static final String JWT_SECRET = TextCodec.BASE64.encode("victory");
|
||||
public static final String[] SECRETS = {"victory","business","available", "shipping", "washington"};
|
||||
public static final String JWT_SECRET = TextCodec.BASE64.encode(SECRETS[new Random().nextInt(SECRETS.length)]);
|
||||
private static final String WEBGOAT_USER = "WebGoat";
|
||||
private static final List<String> expectedClaims = Lists.newArrayList("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role");
|
||||
|
||||
@RequestMapping(path="/gettoken",produces=MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String getSecretToken() {
|
||||
return Jwts.builder()
|
||||
.setIssuer("WebGoat Token Builder")
|
||||
.setAudience("webgoat.org")
|
||||
.setIssuedAt(Calendar.getInstance().getTime())
|
||||
.setExpiration(Date.from(Instant.now().plusSeconds(60)))
|
||||
.setSubject("tom@webgoat.org")
|
||||
.claim("username", "Tom")
|
||||
.claim("Email", "tom@webgoat.org")
|
||||
.claim("Role", new String[] {"Manager", "Project Administrator"})
|
||||
.signWith(SignatureAlgorithm.HS256, JWT_SECRET).compact();
|
||||
}
|
||||
|
||||
@PostMapping("/JWT/secret")
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String token) {
|
||||
@ -69,6 +93,7 @@ public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().feedback("jwt-invalid-token").output(e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<header>
|
||||
<script>
|
||||
$(document).ready(
|
||||
function(){
|
||||
$("#secrettoken").load('/WebGoat/JWT/secret/gettoken');
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</header>
|
||||
<body>
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:JWT_plan.adoc"></div>
|
||||
</div>
|
||||
@ -24,7 +33,7 @@
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST"
|
||||
successCallback="jwtSigningCallback"
|
||||
action="/WebGoat/JWT/votings/reset"
|
||||
action="/WebGoat/JWT/votings"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div class="container-fluid">
|
||||
|
||||
@ -78,6 +87,7 @@
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:JWT_weak_keys"></div>
|
||||
<div id="secrettoken" ></div>
|
||||
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
@ -285,5 +295,6 @@
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -76,7 +76,7 @@ function vote(title) {
|
||||
} else {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'JWT/votings/' + title
|
||||
url: 'JWT/votings/vote/' + title
|
||||
}).then(
|
||||
function () {
|
||||
getVotings();
|
||||
|
@ -6,8 +6,5 @@ dictionary attack is not feasible. Once you have a token you can start an offlin
|
||||
|
||||
=== Assignment
|
||||
|
||||
Given we have the following token try to find out secret key and submit a new key with the userId changed to WebGoat.
|
||||
Given we have the following token try to find out secret key and submit a new key with the username changed to WebGoat.
|
||||
|
||||
```
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.vPe-qQPOt78zK8wrbN1TjNJj3LeX9Qbch6oo23RUJgM
|
||||
```
|
@ -73,7 +73,7 @@ public class JWTVotesEndpointTest extends LessonTest {
|
||||
String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact();
|
||||
|
||||
//Call the reset endpoint
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/reset")
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.cookie(new Cookie("access_token", token)))
|
||||
.andExpect(status().isOk())
|
||||
@ -82,7 +82,7 @@ public class JWTVotesEndpointTest extends LessonTest {
|
||||
|
||||
@Test
|
||||
public void resetWithoutTokenShouldNotWork() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/reset")
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings")
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token"))));
|
||||
@ -153,7 +153,7 @@ public class JWTVotesEndpointTest extends LessonTest {
|
||||
Object[] nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class);
|
||||
int currentNumberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes");
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/vote/Admin lost password")
|
||||
.cookie(cookie))
|
||||
.andExpect(status().isAccepted());
|
||||
result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
|
||||
@ -176,7 +176,7 @@ public class JWTVotesEndpointTest extends LessonTest {
|
||||
|
||||
@Test
|
||||
public void guestShouldNotBeAbleToVote() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/vote/Admin lost password")
|
||||
.cookie(new Cookie("access_token", "")))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
@ -188,7 +188,7 @@ public class JWTVotesEndpointTest extends LessonTest {
|
||||
claims.put("user", "Intruder");
|
||||
String token = Jwts.builder().signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD).setClaims(claims).compact();
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/vote/Admin lost password")
|
||||
.cookie(new Cookie("access_token", token)))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
Reference in New Issue
Block a user