diff --git a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/IntegrationTest.java b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/IntegrationTest.java index 34b48997b..18c8c1ce4 100644 --- a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/IntegrationTest.java +++ b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/IntegrationTest.java @@ -227,14 +227,9 @@ public abstract class IntegrationTest { .extract().path("lessonCompleted"), CoreMatchers.is(expectedResult)); } + //TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are only required to be in the same package) public void checkResults(String prefix) { - Assert.assertThat(RestAssured.given() - .when() - .relaxedHTTPSValidation() - .cookie("JSESSIONID", getWebGoatCookie()) - .get(url("service/lessonoverview.mvc")) - .then() - .statusCode(200).extract().jsonPath().getList("solved"), CoreMatchers.everyItem(CoreMatchers.is(true))); + checkResults(); Assert.assertThat(RestAssured.given() .when() @@ -246,6 +241,16 @@ public abstract class IntegrationTest { } + public void checkResults() { + Assert.assertThat(RestAssured.given() + .when() + .relaxedHTTPSValidation() + .cookie("JSESSIONID", getWebGoatCookie()) + .get(url("service/lessonoverview.mvc")) + .then() + .statusCode(200).extract().jsonPath().getList("solved"), CoreMatchers.everyItem(CoreMatchers.is(true))); + } + public void checkAssignment(String url, ContentType contentType, String body, boolean expectedResult) { Assert.assertThat( RestAssured.given() diff --git a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionMitigationTest.java b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionMitigationTest.java index 40af18a96..d3139f173 100644 --- a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionMitigationTest.java +++ b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionMitigationTest.java @@ -38,6 +38,14 @@ public class SqlInjectionMitigationTest extends IntegrationTest { "}"); checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true); + params.clear(); + params.put("userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--"); + checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true); + + params.clear(); + params.put("userid_sql_only_input_validation_on_keywords", "Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--"); + checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true); + RestAssured.given() .when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()) .contentType(ContentType.JSON) @@ -57,7 +65,6 @@ public class SqlInjectionMitigationTest extends IntegrationTest { params.put("ip", "104.130.219.202"); checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack12a"), params, true); - checkResults("/SqlInjectionMitigations/"); - + checkResults(); } } diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java index 2f0bd3eaa..7220fee56 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/advanced/SqlInjectionLesson6a.java @@ -53,7 +53,7 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint { // The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- } - protected AttackResult injectableQuery(String accountName) { + public AttackResult injectableQuery(String accountName) { String query = ""; try (Connection connection = dataSource.getConnection()) { boolean usedUnion = true; diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson12a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson13.java similarity index 88% rename from webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson12a.java rename to webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson13.java index 3bc935f84..c5a36057c 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson12a.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlInjectionLesson13.java @@ -38,13 +38,13 @@ import java.sql.ResultSet; import java.sql.SQLException; @RestController -@AssignmentHints(value = {"SqlStringInjectionHint-mitigation-12a-1", "SqlStringInjectionHint-mitigation-12a-2", "SqlStringInjectionHint-mitigation-12a-3", "SqlStringInjectionHint-mitigation-12a-4"}) +@AssignmentHints(value = {"SqlStringInjectionHint-mitigation-13-1", "SqlStringInjectionHint-mitigation-13-2", "SqlStringInjectionHint-mitigation-13-3", "SqlStringInjectionHint-mitigation-13-4"}) @Slf4j -public class SqlInjectionLesson12a extends AssignmentEndpoint { +public class SqlInjectionLesson13 extends AssignmentEndpoint { private final DataSource dataSource; - public SqlInjectionLesson12a(DataSource dataSource) { + public SqlInjectionLesson13(DataSource dataSource) { this.dataSource = dataSource; } diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidation.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidation.java new file mode 100644 index 000000000..25dadc0bb --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidation.java @@ -0,0 +1,56 @@ + +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.mitigation; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.sql_injection.advanced.SqlInjectionLesson6a; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@AssignmentHints(value = {"SqlOnlyInputValidation-1", "SqlOnlyInputValidation-2", "SqlOnlyInputValidation-3"}) +public class SqlOnlyInputValidation extends AssignmentEndpoint { + + private final SqlInjectionLesson6a lesson6a; + + public SqlOnlyInputValidation(SqlInjectionLesson6a lesson6a) { + this.lesson6a = lesson6a; + } + + @PostMapping("/SqlOnlyInputValidation/attack") + @ResponseBody + public AttackResult attack(@RequestParam("userid_sql_only_input_validation") String userId) { + if (userId.contains(" ")) { + return failed(this).feedback("SqlOnlyInputValidation-failed").build(); + } + AttackResult attackResult = lesson6a.injectableQuery(userId); + return new AttackResult(attackResult.isLessonCompleted(), attackResult.getFeedback(), attackResult.getOutput(), getClass().getSimpleName()); + } +} diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidationOnKeywords.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidationOnKeywords.java new file mode 100644 index 000000000..961fbf825 --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/mitigation/SqlOnlyInputValidationOnKeywords.java @@ -0,0 +1,56 @@ + +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.mitigation; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.sql_injection.advanced.SqlInjectionLesson6a; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@AssignmentHints(value = {"SqlOnlyInputValidationOnKeywords-1", "SqlOnlyInputValidationOnKeywords-2", "SqlOnlyInputValidationOnKeywords-3"}) +public class SqlOnlyInputValidationOnKeywords extends AssignmentEndpoint { + + private final SqlInjectionLesson6a lesson6a; + + public SqlOnlyInputValidationOnKeywords(SqlInjectionLesson6a lesson6a) { + this.lesson6a = lesson6a; + } + + @PostMapping("/SqlOnlyInputValidationOnKeywords/attack") + @ResponseBody + public AttackResult attack(@RequestParam("userid_sql_only_input_validation_on_keywords") String userId) { + userId = userId.toUpperCase().replace("FROM", "").replace("SELECT", ""); + if (userId.contains(" ")) { + return failed(this).feedback("SqlOnlyInputValidationOnKeywords-failed").build(); + } + AttackResult attackResult = lesson6a.injectableQuery(userId); + return new AttackResult(attackResult.isLessonCompleted(), attackResult.getFeedback(), attackResult.getOutput(), getClass().getSimpleName()); + } +} diff --git a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionMitigations.html b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionMitigations.html index b08a2cfe7..033c20bc9 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionMitigations.html +++ b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjectionMitigations.html @@ -66,14 +66,60 @@