Compare commits

...

11 Commits

Author SHA1 Message Date
c3ed45a733 chore: new release 2025.3 2025-03-11 20:16:10 +01:00
e2f80b18e2 fix: rewrite questions (#2057)
Closes: gh-1178
2025-03-11 20:05:35 +01:00
641f24df9d fix: update filtering internal endpoints in ZAP (#2055) 2025-03-08 12:40:09 +01:00
3b3933b69e chore: bump docker/setup-qemu-action from 3.4.0 to 3.6.0 (#2049)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.4.0 to 3.6.0.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3.4.0...v3.6.0)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 16:55:56 +01:00
05497371db chore: bump docker/build-push-action from 6.14.0 to 6.15.0 (#2050)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.14.0 to 6.15.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.14.0...v6.15.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-05 16:55:47 +01:00
32cf225d6b chore: back to snapshot 2025-03-02 20:47:20 +01:00
affa3f7a1c chore: release 2025.2 2025-03-02 20:37:33 +01:00
e9f79cc739 fix: SQL advanced assignment 5 (#2047)
- Add and show correct hints
- Fix solving the lesson immediately when you register as tom. Now uses `informationMessage` to display a message in the UI
- Add Playwright test

Closes: gh-2045
2025-03-02 20:31:05 +01:00
c37a8e8c19 chore: back to snapshot 2025-03-01 17:16:13 +01:00
5eeeee1e66 chore: extend create release documentation 2025-03-01 17:14:59 +01:00
0d4cc06342 chore: new release 2025.1 2025-03-01 16:38:56 +01:00
30 changed files with 300 additions and 183 deletions

View File

@ -68,7 +68,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Set up QEMU" - name: "Set up QEMU"
uses: docker/setup-qemu-action@v3.4.0 uses: docker/setup-qemu-action@v3.6.0
with: with:
platforms: all platforms: all
@ -82,7 +82,7 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: "Build and push WebGoat" - name: "Build and push WebGoat"
uses: docker/build-push-action@v6.14.0 uses: docker/build-push-action@v6.15.0
with: with:
context: ./ context: ./
file: ./Dockerfile file: ./Dockerfile
@ -95,7 +95,7 @@ jobs:
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }} webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
- name: "Build and push WebGoat desktop" - name: "Build and push WebGoat desktop"
uses: docker/build-push-action@v6.14.0 uses: docker/build-push-action@v6.15.0
with: with:
context: ./ context: ./
file: ./Dockerfile_desktop file: ./Dockerfile_desktop

View File

@ -8,7 +8,8 @@ and 2023.01 in the `pom.xml`.
### Release notes: ### Release notes:
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
committers. In order to fetch the list of issues included use: `git log --graph --pretty='%C(auto)%d%Creset%s' v2023.4..origin/main` committers. In order to fetch the list of issues included use:
`git log --graph --pretty='%C(auto)%d%Creset%s' v2023.4..origin/main`
``` ```
mvn versions:set mvn versions:set
@ -17,5 +18,9 @@ mvn verify
git commit .... git commit ....
git tag v2023.01 git tag v2023.01
git push --tags git push --tags
git push
``` ```
After the release has been tagged and the build process is done. The release notes should be updated in the GitHub
release page.

View File

@ -1,6 +1,24 @@
# WebGoat release notes # WebGoat release notes
## Version 2025.0 ## Version 2025.3
### 🐞 Bug fixes
- Changed URLs imply other exclusion filters for ZAP (#2052)
- XSS lesson stage 12 (2 issues) (#1178)
### 🔄 Technical tasks
- bump docker/setup-qemu-action from 3.4.0 to 3.6.0 (#2049)
- bump docker/build-push-action from 6.14.0 to 6.15.0 (#2050)
## Version 2025.2
### 🐞 Bug fixes
- Fix SQL advanced lesson assignment 5 (#2047)
## Version 2025.1
### 🚀 New functionality ### 🚀 New functionality
@ -43,6 +61,19 @@
- Lots of dependency updates - Lots of dependency updates
## Contributors
Special thanks to the following contributors providing us with a pull request:
- François Capon
- GoogTech HackHuang
- Peter Potrowl
- cap-dev0x
- Benjamin Mouncer
- Jeong Rok Suh
- Rui Melo
- Vandeputte Brice
## Version 2023.8 ## Version 2023.8
### 🚀 New functionality ### 🚀 New functionality

View File

@ -10,7 +10,7 @@
<groupId>org.owasp.webgoat</groupId> <groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat</artifactId> <artifactId>webgoat</artifactId>
<version>2025.0</version> <version>2025.3</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>WebGoat</name> <name>WebGoat</name>

View File

@ -15,17 +15,16 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
startLesson("SqlInjectionAdvanced"); startLesson("SqlInjectionAdvanced");
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.clear();
params.put("username_reg", "tom' AND substring(password,1,1)='t"); params.put("username_reg", "tom' AND substring(password,1,1)='t");
params.put("password_reg", "password"); params.put("password_reg", "password");
params.put("email_reg", "someone@microsoft.com"); params.put("email_reg", "someone@microsoft.com");
params.put("confirm_password", "password"); params.put("confirm_password", "password");
checkAssignmentWithPUT(webGoatUrlConfig.url("SqlInjectionAdvanced/challenge"), params, true); checkAssignmentWithPUT(webGoatUrlConfig.url("SqlInjectionAdvanced/register"), params, false);
params.clear(); params.clear();
params.put("username_login", "tom"); params.put("username_login", "tom");
params.put("password_login", "thisisasecretfortomonly"); params.put("password_login", "thisisasecretfortomonly");
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/challenge_Login"), params, true); checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/login"), params, true);
params.clear(); params.clear();
params.put("userid_6a", "'; SELECT * FROM user_system_data;--"); params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
@ -59,7 +58,5 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
"question_4_solution", "question_4_solution",
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'."); "Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/quiz"), params, true); checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/quiz"), params, true);
checkResults("SqlInjectionAdvanced");
} }
} }

View File

@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors * SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
*/ */
package org.owasp.webgoat.playwright.webgoat; package org.owasp.webgoat.playwright.webgoat.lessons;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@ -15,8 +15,9 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import org.owasp.webgoat.container.lessons.LessonName; import org.owasp.webgoat.container.lessons.LessonName;
import org.owasp.webgoat.playwright.webgoat.PlaywrightTest;
import org.owasp.webgoat.playwright.webgoat.helpers.Authentication; import org.owasp.webgoat.playwright.webgoat.helpers.Authentication;
import org.owasp.webgoat.playwright.webgoat.pages.HttpBasicsLessonPage; import org.owasp.webgoat.playwright.webgoat.pages.lessons.HttpBasicsLessonPage;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class HttpBasicsLessonUITest extends PlaywrightTest { public class HttpBasicsLessonUITest extends PlaywrightTest {

View File

@ -0,0 +1,120 @@
/*
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
* SPDX-License-Identifier: GPL-2.0-or-later
*/
package org.owasp.webgoat.playwright.webgoat.lessons;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Page.GetByRoleOptions;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.owasp.webgoat.container.lessons.LessonName;
import org.owasp.webgoat.playwright.webgoat.PlaywrightTest;
import org.owasp.webgoat.playwright.webgoat.helpers.Authentication;
import org.owasp.webgoat.playwright.webgoat.pages.lessons.LessonPage;
public class SqlInjectionAdvancedUITest extends PlaywrightTest {
private LessonPage lessonPage;
@BeforeEach
void navigateToLesson(Browser browser) {
var lessonName = new LessonName("SqlInjectionAdvanced");
var page = Authentication.sylvester(browser);
this.lessonPage = new LessonPage(page);
lessonPage.resetLesson(lessonName);
lessonPage.open(lessonName);
}
@Test
@DisplayName("Login as Tom with incorrect password")
void loginAsTomWithIncorrectPassword() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Login")).click();
page.locator("[name='username_login']").fill("tom");
page.locator("[name='password_login']").fill("test");
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Log In")).click();
assertThat(lessonPage.getAssignmentOutput())
.containsText("Wrong username or password. Try again.");
}
@Test
@DisplayName("Login as Tom with correct password")
void loginAsTomWithCorrectPassword() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Login")).click();
page.locator("[name='username_login']").fill("tom");
page.locator("[name='password_login']").fill("thisisasecretfortomonly");
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Log In")).click();
lessonPage.isAssignmentSolved(5);
}
@Test
@DisplayName("Register as Tom should show error that Tom already exists")
void registerAsTomShouldDisplayError() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
page.locator("[name='username_reg']").fill("tom");
page.locator("[name='email_reg']").fill("tom@tom.org");
page.locator("[name='password_reg']").fill("test");
page.locator("[name='confirm_password_reg']").fill("test");
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
assertThat(lessonPage.getAssignmentOutput()).containsText("User tom already exists");
}
@Test
@DisplayName(
"Using SQL Injection to register as Tom to guess the password and the guess is correct")
void startGuessingCorrect() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
page.locator("[name='username_reg']").fill("tom' AND substring(password,1,1)='t");
page.locator("[name='email_reg']").fill("tom@tom.org");
page.locator("[name='password_reg']").fill("test");
page.locator("[name='confirm_password_reg']").fill("test");
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
assertThat(lessonPage.getAssignmentOutput())
.containsText("User tom' AND substring(password,1,1)='t already exists");
}
@Test
@DisplayName(
"Using SQL Injection to register as Tom to guess the password and the guess is incorrect")
void startGuessingIncorrect() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
page.locator("[name='username_reg']").fill("tom' AND substring(password,1,1)='a");
page.locator("[name='email_reg']").fill("tom@tom.org");
page.locator("[name='password_reg']").fill("test");
page.locator("[name='confirm_password_reg']").fill("test");
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
assertThat(lessonPage.getAssignmentOutput())
.containsText(
"User tom' AND substring(password,1,1)='a created, please proceed to the login page.");
}
@Test
@DisplayName("Should display correct hints")
void shouldDisplayCorrectHints() {
lessonPage.navigateTo(5);
var page = lessonPage.getPage();
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Show hints")).click();
assertThat(lessonPage.getAssignmentOutput()).containsText("Look at the different");
}
}

View File

@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors * SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
*/ */
package org.owasp.webgoat.playwright.webgoat.pages; package org.owasp.webgoat.playwright.webgoat.pages.lessons;
import com.microsoft.playwright.Locator; import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page; import com.microsoft.playwright.Page;

View File

@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors * SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
*/ */
package org.owasp.webgoat.playwright.webgoat.pages; package org.owasp.webgoat.playwright.webgoat.pages.lessons;
import static org.owasp.webgoat.playwright.webgoat.PlaywrightTest.webGoatUrl; import static org.owasp.webgoat.playwright.webgoat.PlaywrightTest.webGoatUrl;
@ -14,7 +14,7 @@ import org.assertj.core.api.Assertions;
import org.owasp.webgoat.container.lessons.LessonName; import org.owasp.webgoat.container.lessons.LessonName;
@Getter @Getter
class LessonPage { public class LessonPage {
private final Page page; private final Page page;
@ -65,4 +65,8 @@ class LessonPage {
public Locator getAssignmentOutput() { public Locator getAssignmentOutput() {
return page.locator("#lesson-content-wrapper"); return page.locator("#lesson-content-wrapper");
} }
public Locator getHintsOutput() {
return page.locator("#lesson-hint");
}
} }

View File

@ -4,11 +4,9 @@
*/ */
package org.owasp.webgoat.container.assignments; package org.owasp.webgoat.container.assignments;
import org.owasp.webgoat.container.i18n.PluginMessages;
public class AttackResultBuilder { public class AttackResultBuilder {
private boolean lessonCompleted; private boolean assignmentCompleted;
private Object[] feedbackArgs; private Object[] feedbackArgs;
private String feedbackResourceBundleKey; private String feedbackResourceBundleKey;
private String output; private String output;
@ -16,15 +14,8 @@ public class AttackResultBuilder {
private AssignmentEndpoint assignment; private AssignmentEndpoint assignment;
private boolean attemptWasMade = false; private boolean attemptWasMade = false;
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) { public AttackResultBuilder assignmentCompleted(boolean lessonCompleted) {
this.lessonCompleted = lessonCompleted; this.assignmentCompleted = lessonCompleted;
this.feedbackResourceBundleKey = "lesson.completed";
return this;
}
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
this.lessonCompleted = lessonCompleted;
this.feedbackResourceBundleKey = resourceBundleKey;
return this; return this;
} }
@ -55,7 +46,7 @@ public class AttackResultBuilder {
public AttackResult build() { public AttackResult build() {
return new AttackResult( return new AttackResult(
lessonCompleted, assignmentCompleted,
feedbackResourceBundleKey, feedbackResourceBundleKey,
feedbackArgs, feedbackArgs,
output, output,
@ -81,7 +72,7 @@ public class AttackResultBuilder {
*/ */
public static AttackResultBuilder success(AssignmentEndpoint assignment) { public static AttackResultBuilder success(AssignmentEndpoint assignment) {
return new AttackResultBuilder() return new AttackResultBuilder()
.lessonCompleted(true) .assignmentCompleted(true)
.attemptWasMade() .attemptWasMade()
.feedback("assignment.solved") .feedback("assignment.solved")
.assignment(assignment); .assignment(assignment);
@ -99,13 +90,13 @@ public class AttackResultBuilder {
*/ */
public static AttackResultBuilder failed(AssignmentEndpoint assignment) { public static AttackResultBuilder failed(AssignmentEndpoint assignment) {
return new AttackResultBuilder() return new AttackResultBuilder()
.lessonCompleted(false) .assignmentCompleted(false)
.attemptWasMade() .attemptWasMade()
.feedback("assignment.not.solved") .feedback("assignment.not.solved")
.assignment(assignment); .assignment(assignment);
} }
public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) { public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
return new AttackResultBuilder().lessonCompleted(false).assignment(assignment); return new AttackResultBuilder().assignmentCompleted(false).assignment(assignment);
} }
} }

View File

@ -84,7 +84,7 @@ public class CourseConfiguration {
@Bean @Bean
public Course course() { public Course course() {
assignments.stream().forEach(this::attachToLesson); assignments.forEach(this::attachToLesson);
// Check if all assignments are attached to a lesson // Check if all assignments are attached to a lesson
var assignmentsAttachedToLessons = var assignmentsAttachedToLessons =
@ -99,7 +99,7 @@ public class CourseConfiguration {
private List<String> findDiff() { private List<String> findDiff() {
var matchedToLessons = var matchedToLessons =
lessons.stream().flatMap(l -> l.getAssignments().stream()).map(a -> a.getName()).toList(); lessons.stream().flatMap(l -> l.getAssignments().stream()).map(Assignment::getName).toList();
var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList(); var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList();
var diff = new ArrayList<>(allAssignments); var diff = new ArrayList<>(allAssignments);

View File

@ -5,7 +5,7 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced; package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed; import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success; import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import java.sql.*; import java.sql.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -19,13 +19,17 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/**
* @author nbaars
* @since 4/8/17.
*/
@RestController @RestController
@AssignmentHints( @AssignmentHints(
value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"}) value = {
"SqlInjectionChallenge1",
"SqlInjectionChallenge2",
"SqlInjectionChallenge3",
"SqlInjectionChallenge4",
"SqlInjectionChallenge5",
"SqlInjectionChallenge6",
"SqlInjectionChallenge7"
})
@Slf4j @Slf4j
public class SqlInjectionChallenge implements AssignmentEndpoint { public class SqlInjectionChallenge implements AssignmentEndpoint {
@ -35,38 +39,34 @@ public class SqlInjectionChallenge implements AssignmentEndpoint {
this.dataSource = dataSource; this.dataSource = dataSource;
} }
@PutMapping("/SqlInjectionAdvanced/challenge") @PutMapping("/SqlInjectionAdvanced/register")
// assignment path is bounded to class so we use different http method :-) // assignment path is bounded to class so we use different http method :-)
@ResponseBody @ResponseBody
public AttackResult registerNewUser( public AttackResult registerNewUser(
@RequestParam String username_reg, @RequestParam("username_reg") String username,
@RequestParam String email_reg, @RequestParam("email_reg") String email,
@RequestParam String password_reg) @RequestParam("password_reg") String password) {
throws Exception { AttackResult attackResult = checkArguments(username, email, password);
AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);
if (attackResult == null) { if (attackResult == null) {
try (Connection connection = dataSource.getConnection()) { try (Connection connection = dataSource.getConnection()) {
String checkUserQuery = String checkUserQuery =
"select userid from sql_challenge_users where userid = '" + username_reg + "'"; "select userid from sql_challenge_users where userid = '" + username + "'";
Statement statement = connection.createStatement(); Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(checkUserQuery); ResultSet resultSet = statement.executeQuery(checkUserQuery);
if (resultSet.next()) { if (resultSet.next()) {
if (username_reg.contains("tom'")) { attackResult = failed(this).feedback("user.exists").feedbackArgs(username).build();
attackResult = success(this).feedback("user.exists").build();
} else {
attackResult = failed(this).feedback("user.exists").feedbackArgs(username_reg).build();
}
} else { } else {
PreparedStatement preparedStatement = PreparedStatement preparedStatement =
connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)"); connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)");
preparedStatement.setString(1, username_reg); preparedStatement.setString(1, username);
preparedStatement.setString(2, email_reg); preparedStatement.setString(2, email);
preparedStatement.setString(3, password_reg); preparedStatement.setString(3, password);
preparedStatement.execute(); preparedStatement.execute();
attackResult = success(this).feedback("user.created").feedbackArgs(username_reg).build(); attackResult =
informationMessage(this).feedback("user.created").feedbackArgs(username).build();
} }
} catch (SQLException e) { } catch (SQLException e) {
attackResult = failed(this).output("Something went wrong").build(); attackResult = failed(this).output("Something went wrong").build();
@ -75,13 +75,13 @@ public class SqlInjectionChallenge implements AssignmentEndpoint {
return attackResult; return attackResult;
} }
private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) { private AttackResult checkArguments(String username, String email, String password) {
if (StringUtils.isEmpty(username_reg) if (StringUtils.isEmpty(username)
|| StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(email)
|| StringUtils.isEmpty(password_reg)) { || StringUtils.isEmpty(password)) {
return failed(this).feedback("input.invalid").build(); return failed(this).feedback("input.invalid").build();
} }
if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) { if (username.length() > 250 || email.length() > 30 || password.length() > 30) {
return failed(this).feedback("input.invalid").build(); return failed(this).feedback("input.invalid").build();
} }
return null; return null;

View File

@ -9,7 +9,6 @@ import static org.owasp.webgoat.container.assignments.AttackResultBuilder.succes
import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.LessonDataSource;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@ -17,13 +16,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@AssignmentHints(
value = {
"SqlInjectionChallengeHint1",
"SqlInjectionChallengeHint2",
"SqlInjectionChallengeHint3",
"SqlInjectionChallengeHint4"
})
public class SqlInjectionChallengeLogin implements AssignmentEndpoint { public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
private final LessonDataSource dataSource; private final LessonDataSource dataSource;
@ -31,20 +23,22 @@ public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
this.dataSource = dataSource; this.dataSource = dataSource;
} }
@PostMapping("/SqlInjectionAdvanced/challenge_Login") @PostMapping("/SqlInjectionAdvanced/login")
@ResponseBody @ResponseBody
public AttackResult login( public AttackResult login(
@RequestParam String username_login, @RequestParam String password_login) throws Exception { @RequestParam("username_login") String username,
@RequestParam("password_login") String password)
throws Exception {
try (var connection = dataSource.getConnection()) { try (var connection = dataSource.getConnection()) {
var statement = var statement =
connection.prepareStatement( connection.prepareStatement(
"select password from sql_challenge_users where userid = ? and password = ?"); "select password from sql_challenge_users where userid = ? and password = ?");
statement.setString(1, username_login); statement.setString(1, username);
statement.setString(2, password_login); statement.setString(2, password);
var resultSet = statement.executeQuery(); var resultSet = statement.executeQuery();
if (resultSet.next()) { if (resultSet.next()) {
return ("tom".equals(username_login)) return ("tom".equals(username))
? success(this).build() ? success(this).build()
: failed(this).feedback("ResultsButNotTom").build(); : failed(this).feedback("ResultsButNotTom").build();
} else { } else {

View File

@ -1,4 +1,3 @@
lesson.completed=Congratulations. You have successfully completed this lesson.
assignment.solved=Congratulations. You have successfully completed the assignment. assignment.solved=Congratulations. You have successfully completed the assignment.
assignment.not.solved=Sorry the solution is not correct, please try again. assignment.not.solved=Sorry the solution is not correct, please try again.
RestartLesson=Restart this Lesson RestartLesson=Restart this Lesson

View File

@ -1,5 +1,4 @@
#General #General
lesson.completed=Herzlichen Gl\u00fcckwunsch! Sie haben diese Lektion erfolgreich abgeschlossen.
assignment.solved=Herzlichen Gl\u00fcckwunsch! Sie haben diesen Auftrag erfolgreich abgeschlossen. assignment.solved=Herzlichen Gl\u00fcckwunsch! Sie haben diesen Auftrag erfolgreich abgeschlossen.
assignment.not.solved=Die L\u00f6sung ist nicht korrekt, versuchen Sie es erneut. assignment.not.solved=Die L\u00f6sung ist nicht korrekt, versuchen Sie es erneut.

View File

@ -1,5 +1,4 @@
#General #General
lesson.completed=F\u00e9licitations. Vous avez termin\u00e9 cette le\u00e7on avec succ\u00e9s.
RestartLesson=Recommencer cette le\u00e7on RestartLesson=Recommencer cette le\u00e7on
SolutionVideos=Solution vid\u00e9os SolutionVideos=Solution vid\u00e9os
ErrorGenerating=Error generating ErrorGenerating=Error generating

View File

@ -1,4 +1,3 @@
lesson.completed=Gefeliciteerd, je hebt deze les succesvol afgerond.
assignment.solved=Gefeliciteerd, je hebt deze opdracht succesvol afgerond. assignment.solved=Gefeliciteerd, je hebt deze opdracht succesvol afgerond.
assignment.not.solved=Sorry de oplossing is niet correct, probeer het nog eens. assignment.not.solved=Sorry de oplossing is niet correct, probeer het nog eens.
RestartLesson=Herstart de les RestartLesson=Herstart de les

View File

@ -10,7 +10,7 @@ challenge9.title=Changing password
challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0} challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0}
challenge.close=This is not the correct password for Larry, please try again. challenge.close=This is not the correct password for Larry, please try again.
email.send=An e-mail has been send to {0} email.send=An e-mail has been sent to {0}
user.exists=User {0} already exists please try to register with a different username. user.exists=User {0} already exists please try to register with a different username.
user.created=User {0} created, please proceed to the login page. user.created=User {0} created, please proceed to the login page.

View File

@ -1,2 +0,0 @@
EnterYourName=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
Go!=\u0412\u043f\u0435\u0440\u0451\u0434!

View File

@ -1,24 +1,7 @@
==== Setting up browser ==== Setting up browser
If you use the latest ZAP version (>= 2.8.0), you only need to start ZAP and click the browser button to be able to proxy, see image below: As the ZAP setup for proxying localhost varies based on your browser, we recommend following the instructions at: https://www.zaproxy.org/docs/desktop/start/proxies/
After you setup the proxy, you should see the following in OWASP ZAP on the history panel:
{nbsp} +
image::images/zap-browser-button.png[ZAP Start,style="lesson-image"]
{nbsp} +
In the browser type: http://localhost:8080/WebGoat, you should see WebGoat and the OWASP ZAP Heads On Display (if you use OWASP ZAP as the proxy):
{nbsp} +
image::images/loginscreen.png[Browser with HUD,style="lesson-image"]
{nbsp} +
You might notice that this is the Dutch login screen. The browser determines the language settings. For some pages, there will be some local translations. You can contribute to WebGoat and add more for your preferred language. You can disable the Heads On Display by clicking on the highlighted button. You can learn about the OWASP ZAP HUD on their website. For now, we recommend disabling it as it kind of blocks the menu items.
You should see the following in OWASP ZAP on the history panel:
{nbsp} + {nbsp} +

View File

@ -17,7 +17,7 @@ And in the `URL Exc Regex` box type:
[source] [source]
---- ----
.*lesson.*.mvc .*lesson.*.mvc.*
---- ----
Click 'Apply to close the window, and ZAP will now no longer show internal WebGoat requests. Click 'Apply to close the window, and ZAP will now no longer show internal WebGoat requests.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

View File

@ -79,7 +79,7 @@
<div class="col-lg-12"> <div class="col-lg-12">
<form id="login-form" class="attack-form" accept-charset="UNKNOWN" <form id="login-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form" method="POST" name="form"
th:action="@{/SqlInjectionAdvanced/Challenge_Login}" th:action="@{/SqlInjectionAdvanced/login}"
role="form"> role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_login" id="username4" tabindex="1" <input type="text" name="username_login" id="username4" tabindex="1"
@ -115,7 +115,7 @@
</form> </form>
<form id="register-form" class="attack-form" accept-charset="UNKNOWN" <form id="register-form" class="attack-form" accept-charset="UNKNOWN"
method="PUT" name="form" method="PUT" name="form"
th:action="@{/SqlInjectionAdvanced/challenge}" th:action="@{/SqlInjectionAdvanced/register}"
style="display: none;" role="form"> style="display: none;" role="form">
<div class="form-group"> <div class="form-group">
<input type="text" name="username_reg" id="username" tabindex="1" <input type="text" name="username_reg" id="username" tabindex="1"

View File

@ -3,12 +3,8 @@
2.sql.advanced.title=SQL Injection (advanced) 2.sql.advanced.title=SQL Injection (advanced)
3.sql.mitigation.title=SQL Injection (mitigation) 3.sql.mitigation.title=SQL Injection (mitigation)
NoResultsMatched=Wrong username or password. Try again.
SqlInjectionChallenge1=Look at the different response you receive from the server ResultsButNotTom=Try to log in as Tom!
SqlInjectionChallenge2=The vulnerability is on the register form
SqlInjectionChallenge3=Use tooling to automate this attack
NoResultsMatched=No results matched, try again.
ResultsButNotTom=Try To login as Tom!
sql-injection.2.success=You have succeeded! sql-injection.2.success=You have succeeded!
sql-injection.2.failed=Something went wrong! You got no results, check your SQL Statement and the table above. sql-injection.2.failed=Something went wrong! You got no results, check your SQL Statement and the table above.
@ -100,10 +96,13 @@ SqlStringInjectionHint-mitigation-13-2=Intercept the request and try to specify
SqlStringInjectionHint-mitigation-13-3=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens SqlStringInjectionHint-mitigation-13-3=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
SqlStringInjectionHint-mitigation-13-4=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens SqlStringInjectionHint-mitigation-13-4=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
SqlInjectionChallengeHint1=The table name is randomized at each start of WebGoat, try to figure out the name first. SqlInjectionChallenge1=Look at the different response you receive from the server when you try different entries
SqlInjectionChallengeHint2=Find the field which is vulnerable to SQL injection use that to change the password. SqlInjectionChallenge2=Does the register form give you any indication a user already exists?
SqlInjectionChallengeHint3=Change the password through an UPDATE Statement. SqlInjectionChallenge3=Try to guess the password of the user 'tom' one character at a time
SqlInjectionChallengeHint4=The vulnerable field is the username field of the register form. SqlInjectionChallenge4=Use substring(column, start, length) to get the password of the user 'tom' one character at a time
SqlInjectionChallenge5=Use tom' AND substring(password,1,1)='a for the guess of the first character of the password
SqlInjectionChallenge6=It is important to look at the different responses you receive from the server when you try different entries
SqlInjectionChallenge7=You can use tooling to automate this attack
SqlOnlyInputValidation-failed=Using spaces is not allowed! SqlOnlyInputValidation-failed=Using spaces is not allowed!
SqlOnlyInputValidation-1=Spaces are rejected, try to find a way around this restriction SqlOnlyInputValidation-1=Spaces are rejected, try to find a way around this restriction

View File

@ -1,7 +1,7 @@
#StringSqlInjection.java #StringSqlInjection.java
StringSqlInjectionSecondStage=Da sie nun erfolgreich eine SQL Injection durchgef\u00fchrt haben, versuchen Sie denselben Typ von Angriff auf eine parametrisierte Anfrage. Starten Sie Diese Lektion neu, wenn Sie zur verwundbaren SQL Anfrage gelangen m\u00f6chten. StringSqlInjectionSecondStage=Da sie nun erfolgreich eine SQL Injection durchgef\u00fchrt haben, versuchen Sie denselben Typ von Angriff auf eine parametrisierte Anfrage. Starten Sie Diese Lektion neu, wenn Sie zur verwundbaren SQL Anfrage gelangen m\u00f6chten.
EnterLastName=Geben Sie Ihren Nachnamen ein: EnterLastName=Geben Sie Ihren Nachnamen ein:
NoResultsMatched=Keine Resultate gefunden, versuchen Sie es erneut NoResultsMatched=Falscher Benutzername oder falsches Passwort. Versuchen Sie es erneut.
SqlStringInjectionHint1=The application is taking your input and inserting it at the end of a pre-formed SQL command. SqlStringInjectionHint1=The application is taking your input and inserting it at the end of a pre-formed SQL command.
SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName" SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true

View File

@ -1,7 +1,7 @@
#StringSqlInjection.java #StringSqlInjection.java
StringSqlInjectionSecondStage=Maintenant que vous avez r\u00e9alis\u00e9 une injection SQL avec succ\u00e8s, essayer le m\u00eame type d'attaque sur une requ\u00eate param\u00e9tr\u00e9e. Red\u00e9marrez la le\u00e7on si vous souhaitez revenir \u00e0 la requ\u00eate injectable. StringSqlInjectionSecondStage=Maintenant que vous avez r\u00e9alis\u00e9 une injection SQL avec succ\u00e8s, essayer le m\u00eame type d'attaque sur une requ\u00eate param\u00e9tr\u00e9e. Red\u00e9marrez la le\u00e7on si vous souhaitez revenir \u00e0 la requ\u00eate injectable.
EnterLastName=Entrez votre nom : EnterLastName=Entrez votre nom :
NoResultsMatched=Aucun r\u00e9sultat correspondant. Essayez encore. NoResultsMatched=Aucun nom d'utilisateur ou mot de passe incorrect. Essayez encore.
SqlStringInjectionHint1=L'application r\u00e9cup\u00e8re votre saisie et l'ins\u00e8re \u00e0 la fin d'une commande SQL pr\u00e9-form\u00e9e. SqlStringInjectionHint1=L'application r\u00e9cup\u00e8re votre saisie et l'ins\u00e8re \u00e0 la fin d'une commande SQL pr\u00e9-form\u00e9e.
SqlStringInjectionHint2=Voici le code de la requ\u00eate assembl\u00e9e et ex\u00e9cut\u00e9e par WebGoat :<br><br> "SELECT * FROM user_data WHERE last_name = "accountName" SqlStringInjectionHint2=Voici le code de la requ\u00eate assembl\u00e9e et ex\u00e9cut\u00e9e par WebGoat :<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
SqlStringInjectionHint3=Les commandes SQL compos\u00e9es peuvent \u00eatre assembl\u00e9es en associant de multiples conditions au moyen de mots-cl\u00e9 tels que AND et OR. Essayez d'assembler une condition qui sera toujours r\u00e9solue \u00e0 vrai. SqlStringInjectionHint3=Les commandes SQL compos\u00e9es peuvent \u00eatre assembl\u00e9es en associant de multiples conditions au moyen de mots-cl\u00e9 tels que AND et OR. Essayez d'assembler une condition qui sera toujours r\u00e9solue \u00e0 vrai.

View File

@ -1,8 +0,0 @@
#StringSqlInjection.java
StringSqlInjectionSecondStage=\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0434\u0430\u0447\u043d\u043e \u043f\u0440\u043e\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c SQL-\u0438\u043d\u044a\u0435\u043a\u0446\u0438\u044e, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u044d\u0442\u043e \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c. \u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0443\u0440\u043e\u043a \u0437\u0430\u043d\u043e\u0432\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0432\u043d\u043e\u0432\u044c \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0435 \u043f\u043e\u043b\u0435.
EnterLastName=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0443 \u0444\u0430\u043c\u0438\u043b\u0438\u044e:
NoResultsMatched=\u041d\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0439. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.
SqlStringInjectionHint1=\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0440\u0451\u0442 \u0442\u043e \u0447\u0442\u043e \u0432\u044b \u0432\u0432\u043e\u0434\u0438\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043a\u043e\u043d\u0435\u0446 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.
SqlStringInjectionHint2=\u0412\u043e\u0442 \u043a\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f WebGoat`\u043e\u043c:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
SqlStringInjectionHint3=\u0426\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0434\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u043a\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432 \u043a\u0430\u043a AND \u0438 OR. \u041f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0435 SQL-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u0443.
SqlStringInjectionHint4=\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u0432\u0435\u0441\u0442\u0438 [ smith' OR '1' = '1 ].

View File

@ -1,13 +1,15 @@
{ {
"questions": [{ "questions": [
{
"text": "What is the difference between a prepared statement and a statement?", "text": "What is the difference between a prepared statement and a statement?",
"solutions": { "solutions": {
"1": "Prepared statements are statements with hard-coded parameters.", "1": "Prepared statements are statements with hard-coded parameters.",
"2": "Prepared statements are not stored in the database.", "2": "Prepared statements are not stored in the database.",
"3": "A statement is faster.", "3": "A statement is faster executes faster than a prepared statement.",
"4": "A statement has got values instead of a prepared statement" "4": "A statement includes actual values, whereas a prepared statement uses placeholders."
} }
}, { },
{
"text": "Which one of the following characters is a placeholder for variables?", "text": "Which one of the following characters is a placeholder for variables?",
"solutions": { "solutions": {
"1": "*", "1": "*",
@ -15,29 +17,33 @@
"3": "?", "3": "?",
"4": "!" "4": "!"
} }
}, { },
{
"text": "How can prepared statements be faster than statements?", "text": "How can prepared statements be faster than statements?",
"solutions": { "solutions": {
"1": "They are not static so they can compile better written code than statements.", "1": "Prepared statements are not static, allowing them to be optimized more efficiently than regular statements.",
"2": "Prepared statements are compiled once by the database management system waiting for input and are pre-compiled this way.", "2": "Prepared statements are compiled once by the database management system and then reused with different inputs, reducing compilation overhead.",
"3": "Prepared statements are stored and wait for input it raises performance considerably.", "3": "Since prepared statements are stored and wait for input, they improve performance significantly.",
"4": "Oracle optimized prepared statements. Because of the minimal use of the databases resources it is faster." "4": "Oracle optimizes prepared statements, making them faster by minimizing the use of database resources."
} }
}, { },
"text": "How can a prepared statement prevent SQL-Injection?", {
"text": "How do prepared statements help prevent SQL injection?",
"solutions": { "solutions": {
"1": "Prepared statements have got an inner check to distinguish between input and logical errors.", "1": "Prepared statements have built-in mechanisms to distinguish between user input and SQL logic, preventing malicious manipulation.",
"2": "Prepared statements use the placeholders to make rules what input is allowed to use.", "2": "Prepared statements use placeholders to enforce rules on allowed input, reducing the risk of SQL injection.",
"3": "Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data.", "3": "Placeholders prevent user input from being directly appended to the SQL query, ensuring a clear separation between code and data.",
"4": "Prepared statements always read inputs literally and never mixes it with its SQL commands." "4": "Prepared statements treat all user input as literal values, never mixing it with SQL commands."
} }
}, { },
"text": "What happens if a person with malicious intent writes into a register form :Robert); DROP TABLE Students;-- that has a prepared statement?", {
"text": "What happens if a person with malicious intent enters the following input into a registration form that uses a prepared statement? Input: Robert); DROP TABLE Students;--",
"solutions": { "solutions": {
"1": "The table Students and all of its content will be deleted.", "1": "The Students table and all its data will be deleted.",
"2": "The input deletes all students with the name Robert.", "2": "The input deletes all students named Robert.",
"3": "The database registers 'Robert' and deletes the table afterwards.", "3": "The database registers Robert and then deletes the table.",
"4": "The database registers 'Robert' ); DROP TABLE Students;--'." "4": "The database treats the entire input as a plain string: Robert); DROP TABLE Students;-- without executing it as SQL."
} }
}] }
]
} }

View File

@ -1,19 +1,19 @@
{ {
"questions": [{ "questions": [{
"text": "Are trusted websites immune to XSS attacks?", "text": "Is a well known website, like Netflix, immune to XSS attacks?",
"solutions": { "solutions": {
"1": "Yes they are safe because the browser checks the code before executing.", "1": "Yes, they are safe because the browser checks the code before executing.",
"2": "Yes because Google has got an algorithm that blocks malicious code.", "2": "Yes, because Google has got an algorithm that blocks malicious code.",
"3": "No because the script that is executed will break through the defense algorithm of the browser.", "3": "No, because the script that is executed will break through the defense algorithm of the browser.",
"4": "No because the browser trusts the website if it is acknowledged trusted, then the browser does not know that the script is malicious." "4": "No, because the browser trusts the website if it is acknowledged trusted, then the browser does not know that the script is malicious."
} }
}, { }, {
"text": "When do XSS attacks occur?", "text": "When do XSS attacks occur?",
"solutions": { "solutions": {
"1": "Data enters a web application through a trusted source.", "1": "When malicious scripts are injected into a website's server-side code.",
"2": "Data enters a browser application through the website.", "2": "When a user submits sensitive information without encryption.",
"3": "The data is included in dynamic content that is sent to a web user without being validated for malicious content.", "3": "When a website fails to validate or sanitize user input, allowing malicious scripts to be executed in a user's browser.",
"4": "The data is excluded in static content that way it is sent without being validated." "4": "When a website uses outdated SSL/TLS protocols."
} }
}, { }, {
"text": "What are Stored XSS attacks?", "text": "What are Stored XSS attacks?",
@ -27,17 +27,17 @@
"text": "What are Reflected XSS attacks?", "text": "What are Reflected XSS attacks?",
"solutions": { "solutions": {
"1": "Reflected attacks reflect malicious code from the database to the web server and then reflect it back to the user.", "1": "Reflected attacks reflect malicious code from the database to the web server and then reflect it back to the user.",
"2": "They reflect the injected script off the web server. That occurs when input sent to the web server is part of the request.", "2": "They reflect the injected script off the web server. That occurs when input sent to the web server is part of the response.",
"3": "Reflected attacks reflect from the firewall off to the database where the user requests information from.", "3": "Reflected attacks reflect from the firewall off to the database where the user requests information from.",
"4": "Reflected XSS is an attack where the injected script is reflected off the database and web server to the user." "4": "Reflected XSS is an attack where the injected script is reflected off the database and web server to the user."
} }
}, { }, {
"text": "Is JavaScript the only way to perform XSS attacks?", "text": "Is JavaScript the only way to perform XSS attacks?",
"solutions": { "solutions": {
"1": "Yes you can only make use of tags through JavaScript.", "1": "Yes, you can only make use of tags through JavaScript.",
"2": "Yes otherwise you cannot steal cookies.", "2": "Yes, otherwise you cannot steal cookies.",
"3": "No there is ECMAScript too.", "3": "No, there is ECMAScript too.",
"4": "No there are many other ways. Like HTML, Flash or any other type of code that the browser executes." "4": "No, there are many other ways. Like HTML, Flash or any other type of code that the browser executes."
} }
}] }]
} }