Refactoring (#1201)

* Some initial refactoring

* Make it one application

* Got it working

* Fix problem on Windows

* Move WebWolf

* Move first lesson

* Moved all lessons

* Fix pom.xml

* Fix tests

* Add option to initialize a lesson

This way we can create content for each user inside a lesson. The initialize method will be called when a new user is created or when a lesson reset happens

* Clean up pom.xml files

* Remove fetching labels based on language.

We only support English at the moment, all the lesson explanations are written in English which makes it very difficult to translate. If we only had labels it would make sense to support multiple languages

* Fix SonarLint issues

* And move it all to the main project

* Fix for documentation paths

* Fix pom warnings

* Remove PMD as it does not work

* Update release notes about refactoring

Update release notes about refactoring

Update release notes about refactoring

* Fix lesson template

* Update release notes

* Keep it in the same repo in Dockerhub

* Update documentation to show how the connection is obtained.

Resolves: #1180

* Rename all integration tests

* Remove command from Dockerfile

* Simplify GitHub actions

Currently, we use a separate actions for pull-requests and branch build.
This is now consolidated in one action.
The PR action triggers always, it now only trigger when the PR is
opened and not in draft.
Running all platforms on a branch build is a bit too much, it is better
 to only run all platforms when someone opens a PR.

* Remove duplicate entry from release notes

* Add explicit registry for base image

* Lesson scanner not working when fat jar

When running the fat jar we have to take into account we
are reading from the jar file and not the filesystem. In
this case you cannot use `getFile` for example.

* added info in README and fixed release docker

* changed base image and added ignore file

Co-authored-by: Zubcevic.com <rene@zubcevic.com>
This commit is contained in:
Nanne Baars
2022-04-09 14:56:12 +02:00
committed by GitHub
parent f3d8206a07
commit 711649924b
1130 changed files with 3540 additions and 7643 deletions

View File

@ -0,0 +1,75 @@
/* Component: Posts */
.post .post-heading {
height: 95px;
padding: 20px 15px;
}
.post .post-heading .avatar {
width: 60px;
height: 60px;
display: block;
margin-right: 15px;
}
.post .post-heading .meta .title {
margin-bottom: 0;
}
.post .post-heading .meta .title a {
color: black;
}
.post .post-heading .meta .title a:hover {
color: #aaaaaa;
}
.post .post-heading .meta .time {
margin-top: 8px;
color: #999;
}
.post .post-image .image {
width:20%;
height: 40%;
}
.post .post-description {
padding: 5px;
}
.post .post-footer {
border-top: 1px solid #ddd;
padding: 15px;
}
.post .post-footer .input-group-addon a {
color: #454545;
}
.post .post-footer .comments-list {
padding: 0;
margin-top: 20px;
list-style-type: none;
}
.post .post-footer .comments-list .comment {
display: block;
width: 100%;
margin: 20px 0;
}
.post .post-footer .comments-list .comment .avatar {
width: 35px;
height: 35px;
}
.post .post-footer .comments-list .comment .comment-heading {
display: block;
width: 100%;
}
.post .post-footer .comments-list .comment .comment-heading .user {
font-size: 14px;
font-weight: bold;
display: inline;
margin-top: 0;
margin-right: 10px;
}
.post .post-footer .comments-list .comment .comment-heading .time {
font-size: 12px;
color: #aaa;
margin-top: 0;
display: inline;
}
.post .post-footer .comments-list .comment .comment-body {
margin-left: 50px;
}
.post .post-footer .comments-list .comment > .comments-list {
margin-left: 50px;
}

View File

@ -0,0 +1,13 @@
== Concept
After learning what Cross-Site Scripting (XSS) is and how it works,
you will know to learn how you can defend against it.
== Goals
* The user will understand the best practices for defending against XSS injection attacks
* The user will demonstrate knowledge on:
** XSS mitigation

View File

@ -0,0 +1,8 @@
== Concept
After looking at Reflected XSS in the previous lesson, we are now going to take a closer look at another form of Cross-Site Scripting Attack: Stored XSS.
== Goals
* The user will learn what Stored XSS is
* The user will demonstrate knowledge on:
** Stored XSS injection

View File

@ -0,0 +1,32 @@
== What is XSS?
Cross-Site Scripting (also known as XSS) is a vulnerability/flaw that combines the allowance of HTML/script tags as input that renders into a browser without encoding or sanitization.
=== Cross-Site Scripting (XSS) is the most prevalent and pernicious web application security issue
While there is a simple well-known defense for this attack, there are still many instances on the web. Coverage of fixes also tends to be a problem in terms of fixing it. We will talk more about the defense in a little bit.
=== XSS has significant impact
Especially as 'Rich Internet Applications' are more and more commonplace, privileged function calls linked to via JavaScript may be compromised.
And if not adequately protected, sensitive data (such as your authentication cookies) can be stolen and used for someone else's purpose.
==== Quick examples:
* From the JavaScript console in the developer tools of the browser (Chrome, Firefox)
+
----
alert("XSS Test");
alert(document.cookie);
----
* Any data field returned to the client is potentially injectable
+
----
<script>alert("XSS Test")</script>
----
== Try It! Using Chrome or Firefox
* Open a second tab and use the same URL as this page you are currently on (or any URL within this instance of WebGoat).
* On the second tab, open the JavaScript console in the developer tools and type: `alert(document.cookie);`.
* The cookies should be the same on each tab.

View File

@ -0,0 +1,15 @@
== Most common locations
* Search fields that echo a search string back to the user
* Input fields that echo user data
* Error messages that return user-supplied text
* Hidden fields that contain user-supplied data
* Any page that displays user-supplied data
** Message boards
** Free form comments
* HTTP Headers

View File

@ -0,0 +1,19 @@
== Why should we care?
=== XSS attacks may result in
* Stealing session cookies
* Creating false requests
* Creating false fields on a page to collect credentials
* Redirecting your page to a "non-friendly" site
* Creating requests that masquerade as a valid user
* Stealing of confidential information
* Execution of malicious code on an end-user system (active scripting)
* Insertion of hostile and inappropriate content
+
----
<img src="http://malicious.site.com/image.jpg/>
">GoodYear recommends buying BridgeStone tires...
----
=== XSS attacks add validity to phishing attacks
* A valid domain is used in the URL

View File

@ -0,0 +1,16 @@
== Types of XSS
=== Reflected
* Malicious content from a user request is displayed to the user in a web browser
* Malicious content is written into the page after from server response
* Social engineering is required
* Runs with browser privileges inherited from the user in a browser
=== DOM-based (also technically reflected)
* Client-side scripts use malicious content from a user request to write HTML to its page
* Similar to reflected XSS
* Runs with browser privileges inherited from the user in a browser
=== Stored or persistent
* Malicious content is stored on the server ( in a database, file system, or other objects) and later displayed to users in a web browser
* Social engineering is not required

View File

@ -0,0 +1,9 @@
== Reflected XSS scenario
* Attacker sends a malicious URL to the victim
* Victim clicks on the link that loads a malicious web page
* The malicious script embedded in the URL executes in the victims browser
** The script steals sensitive information, like the session id, and releases it to the attacker
*Victim does not realize attack occurred*

View File

@ -0,0 +1,8 @@
== Try It! Reflected XSS
The assignment's goal is to identify which field is susceptible to XSS.
It is always a good practice to validate all input on the server side. XSS can occur when unvalidated user input gets used in an HTTP response.
In a reflected XSS attack, an attacker can craft a URL with the attack script and post it to another website, email it, or otherwise get a victim to click on it.
An easy way to find out if a field is vulnerable to an XSS attack is to use the `alert()` or `console.log()` methods. Use one of them to find out which field is vulnerable.

View File

@ -0,0 +1,10 @@
== Self XSS or reflected XSS?
You should have been able to execute the script with the last example. At this point, it is considered 'self XSS,' though.
Why is that?
That is because no link triggers that XSS.
You can try it yourself to see what happens ... go to:
link:/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field1=<script>alert('my%20javascript%20here')</script>4128+3214+0002+1999&field2=111["/WebGoat/CrossSiteScripting/attack5a?QTY1=1&QTY2=1&QTY3=1&QTY4=1&field1=<script>alert('my%20javascript%20here')</script>4128+3214+0002+1999&field2=111",window=_blank]

View File

@ -0,0 +1,14 @@
== Reflected and DOM-Based XSS
DOM-based XSS is another form of reflected XSS. Both are triggered by sending a link with inputs reflected in the browser.
The difference between DOM and 'traditional' reflected XSS is that, with DOM, the payload will never go to the server. The client will only ever process it.
* Attacker sends a malicious URL to the victim
* Victim clicks on the link
* That link may load a malicious web page or a web page they use (are logged into?) that has a vulnerable route/handler
* If it's a malicious web page, it may use its own JavaScript to attack another page/URL with a vulnerable route/handler
* The vulnerable page renders the payload and executes an attack in the user's context on that page/site
* Attacker's malicious script may run commands with the privileges of local account
*Victim does not realize attack occurred* ... Malicious attackers don't use &lt;script&gt;alert('xss')&lt;/ script&gt;

View File

@ -0,0 +1,15 @@
== Identify potential for DOM-Based XSS
DOM-Based XSS can usually be found by looking for the route configurations in the client-side code.
Look for a route that takes inputs that are "reflected" to the page.
For this example, you will want to look for some 'test' code in the route handlers (WebGoat uses backbone as its primary JavaScript library).
Sometimes, test code gets left in production (and often test code is simple and lacks security or quality controls!).
Your objective is to find the route and exploit it. First though, what is the base route? As an example, look at the URL for this lesson ...
it should look something like /WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9. The 'base route' in this case is:
*start.mvc#lesson/*
The *CrossSiteScripting.lesson/9* after that are parameters that are processed by the JavaScript route handler.
So, what is the route for the test code that stayed in the app during production?
To answer this question, you have to check the JavaScript source.

View File

@ -0,0 +1,11 @@
== Try It! DOM-Based XSS
Some attacks are "blind." Fortunately, you have the server running here, so you can tell if you are successful.
Use the route you just found and see if you can use it to reflect a parameter from the route without encoding to execute an internal function in WebGoat.
The function you want to execute is:
*webgoat.customjs.phoneHome()*
Sure, you could use console/debug to trigger it, but you need to trigger it via a URL in a new tab.
Once you trigger it, a subsequent response will come to your browser's console with a random number. Put that random number below.

View File

@ -0,0 +1,18 @@
== DOM-Based XSS Example
----
<script language="javascript"> function resetVals(form)
{
var temp = document.URL;
var idx = temp.indexOf('login?');
var errorMsg = temp.substring(idx+1,temp.length).split('=');
if (errorMsg\[1\].indexOf("/login?")!=-1)
{
var index = errorMsg\[1\].indexOf("/login?");
var msg = errorMsg\[1\].substring(index,length-1);
errorMsg\[1\] = msg;
}
document.write('<b>'+errorMsg\[1\]+'</b>');
}
</script>
----

View File

@ -0,0 +1,11 @@
== Stored XSS
Stored Cross-Site Scripting is different in that the payload is persisted (stored) instead of passed/injected via a link.
== Stored XSS Scenario
* Attacker posts malicious script to a message board
* Message is stored in a server database
* Victim reads the message
* The malicious script embedded in the message board post executes in the victims browser
** The script steals sensitive information, like the session id, and releases it to the attacker
*Victim does not realize attack occurred*

View File

@ -0,0 +1,6 @@
See the comments below.
Add a comment with a JavaScript payload. Again ... you want to call the _webgoat.customjs.phoneHome_ function.
As an attacker (offensive security), keep in mind that most apps will not have such a straightforwardly named compromise.
Also, you may have to find a way to load your JavaScript dynamically to achieve the goal of extracting data fully.

View File

@ -0,0 +1,3 @@
Watching in your browser's developer tools or your proxy, the output should include a value starting with 'phoneHome Response is ...."
Put that value below to complete this exercise. Note that each subsequent call to the _phoneHome_ method will change that value.
You may need to ensure you have the most recent one.

View File

@ -0,0 +1,27 @@
== XSS defense
=== Why?
Hopefully, we have covered that by now. Bottom line, you do not want someone else's code running in the context of your users and their logged-in session
=== What to encode?
The basic premise of defending against XSS is *output encoding* any untrusted input to the screen.
That may be changing with more sophisticated attacks, but it is still the best defense we currently have. *AND* ... *context matters*
Another word on 'untrusted input.' If in doubt, treat everything (even data you populated in your DB as untrusted).
Sometimes data is shared across multiple systems, and what you think is your data may not have been created by you/your team.
=== When/Where?
Encode *as the data is sent to the browser* (not in your persisted data). In the case of *Single Page Apps (SPA's), you will need to encode
in the client*. Consult your framework/library for details, but some resources will be provided on the next page.
=== How?
* Encode as HTML Entities in HTML Body
* Encode as HTML Entities in HTML Attribute
* Encode for JavaScript if outputting user input to JavaScript (but think about that ... you are outputting user input into JavaScript on your page!!)
*DO NOT* try to blacklist/negative filter on strings like '<script>' and so forth.
...See the next page for some recommended resources and reading on defending against XSS

View File

@ -0,0 +1,44 @@
== What is encoding?
Not trusting user input means validating data for type, length, format, and range whenever it passes through a trust boundary,
say from a web form to an application script, then encode it before redisplay in a dynamic page.
In practice, this means that you need to review every point on your site where user-supplied data is handled and processed and
ensure that, before being passed back to the user, any values accepted from the client side are checked, filtered, and encoded.
Client-side validation cannot be relied upon, but user input can be forced down to a minimal alphanumeric set with server-side
processing before being used by a web application in any way.
== Escaping
Escaping means that you convert (or mark) key characters of the data to prevent it from being interpreted in a dangerous context.
In the case of HTML output, you need to convert the < and > characters (among others) to prevent any malicious code from rendering.
Escaping these characters involves turning them into their entity equivalents \&lt; and \&gt;,
which will not be interpreted as HTML tags by a browser.
== Special characters
You need to encode special characters like "<" and ">" before they are redisplayed if they are received from user input.
For example, encoding "<" and ">" ensures a browser will display <script> but not execute it.
In conjunction with encoding, your web pages must always define their character set so the browser will not interpret
special character encodings from other character sets.
Cross-site scripting attacks usually occur when you manage to sneak a script (usually javascript) onto someone else's website, where
it can run maliciously.
=== Relevant XML/HTML special characters
|===
|Char |Escape string |
|< |\&lt;|
|> |\&gt;|
|" |\&quot;|
|' |\&#x27;|
|& |\&amp;|
|/ |\&#x2F;|
|===

View File

@ -0,0 +1,68 @@
== Reflective XSS
See the HTML file below, which passes data to a JSP file.
[source,html]
-------------------------------------------------------
<html>
<body>
<form action = "main.jsp" method = "POST">
First Name: <input type = "text" name = "first_name">
<br />
Last Name: <input type = "text" name = "last_name" />
<input type = "submit" value = "Submit" />
</form>
</body>
</html>
-------------------------------------------------------
Here is the JSP file:
[source,html]
-------------------------------------------------------
<html>
<head>
<title>Using GET and POST Method to Read Form Data</title>
</head>
<body>
<h1>Using POST Method to Read Form Data</h1>
<table>
<tbody>
<tr>
<td><b>First Name:</b></td>
<td><%= request.getParameter("first_name")%></td>
</tr>
<tr>
<td><b>Last Name:</b></td>
<td>
<%= request.getParameter("last_name")%>
</td>
</tr>
</tbody>
</table>
</body>
</html>
-------------------------------------------------------
As you can see the JSP file prints unfiltered user input which is never a good idea.
You want people to access the page like this:
----
http://hostname.com/mywebapp/main.jsp?first_name=John&last_name=Smith
----
But what happens if someone uses this link:
----
http://hostname.com/mywebapp/main.jsp?first_name=<script>alert("XSS Test")</script>
----
=== It is your turn!
Try to prevent this kind of XSS by escaping the URL parameters in the JSP file:

View File

@ -0,0 +1,49 @@
== Stored XSS
One way to prevent stored XSS is the usage of https://www.owasp.org/index.php/Category:OWASP_AntiSamy_Project[OWASP AntiSamy]. AntiSamy can produce a "clean" string based on an adjustable policy file.
See the java class below, which saves a comment into a database.
[source,java]
-------------------------------------------------------
public class MyCommentDAO {
public static void addComment(int threadID, int userID, String newComment) {
String sql = "INSERT INTO COMMENTS(THREADID, USERID, COMMENT) VALUES(?,?,?);";
try {
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setInt(1, threadID);
stmt.setInt(2, userID);
stmt.setString(3, newComment);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
-------------------------------------------------------
And here is a Java class that uses the addComment function
[source,java]
-------------------------------------------------------
import org.owasp.validator.html.*;
import MyCommentDAO;
public class AntiSamyController {
...
public void saveNewComment(int threadID, int userID, String newComment){
MyCommentDAO.addComment(threadID, userID, newComment);
}
...
}
-------------------------------------------------------
As you can see the Java file stores unfiltered user input into the database.
You have the whole malicious code stored in your database now.
== It is your turn!
Try to prevent this kind of XSS by creating a clean string inside the saveNewComment() function. Use the "antisamy-slashdot.xml" as a policy file for this example:

View File

@ -0,0 +1,46 @@
== XSS defense resources
=== Java OWASP Encoder
Do not be bothered by the incubator status on this project. Use it if you are doing Java web apps and defending against XSS. Use this
link: https://www.owasp.org/index.php/OWASP_Java_Encoder_Project
=== General XSS prevention Cheat Sheet
link: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
=== DOM XSS Prevention Cheat Sheet
link: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
=== XSS Filter Evasion
Good to know your enemy ...
link https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
=== Javascript Framework Specifics
Encoding in the client can be tricky. Here are some resources to help with that. If you do not see your framework below (e.g., Ember, React, ???) and would like to contribute or suggest something
stop by https://github.com/WebGoat/WebGoat and file an issue (preferably with some recommendations/links) or fork and submit a pull request.
==== jQuery
be aware if you are using something like:
_$selector.html(userInputHere)_,
you are in danger. If you want to use that, ensure you are doing something more like:
_$selector.html(someEncodeHtmlMethod(userInputHere))_
OR
_$selector.*text*(someEncodeHtmlMethod(userInputHere))_
If you only want the text of what is output by the user (http://stackoverflow.com/questions/9735045/is-jquery-text-method-xss-safe#9735118)
==== Backbone.js
(One character can make such a difference)
http://underscorejs.org/#template
https://nvisium.com/blog/2015/05/21/dont-break-your-backbone-xss-mitigation.html
==== Angular
Angular has sought to escape by default, but the expression language has proven to have 'sandbox' escapes. Best to check
details of the version you are using and consult starting here: https://docs.angularjs.org/guide/security

View File

@ -0,0 +1,14 @@
== Concept
This lesson describes what Cross-Site Scripting (XSS) is and how it can be used to perform tasks that were not the developer's original intent.
== Goals
* The user should have a basic understanding of what XSS is and how it works
* The user will learn what Reflected XSS is
* The user will demonstrate knowledge on:
** Reflected XSS injection
** DOM-based XSS injection

View File

@ -0,0 +1 @@
Now it is time for a quiz! It is recommended to check the OWASP Cross-Site Scripting explanations https://owasp.org/www-community/attacks/xss/. Answer all questions correctly to complete the assignment.

View File

@ -0,0 +1,181 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_plan.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content1.adoc"></div>
<div class="attack-container">
<div id="lessonContent">
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/CrossSiteScripting/attack1">
<table>
<tr>
<td><input type="checkbox" name="checkboxAttack1"> The cookies are the same on each tab </td>
<td><input
name="answer" value="Submit" type="SUBMIT"/></td>
<td></td>
</tr>
</table>
</form>
</div>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content2.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content3.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content4.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content5.adoc"></div>
<img align="middle" th:src="@{/images/Reflected-XSS.png}" />
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content5a.adoc"></div>
<div class="attack-container">
<div id="lessonContent">
<form class="attack-form" accept-charset="UNKNOWN"
method="GET" name="xss-5a"
action="/WebGoat/CrossSiteScripting/attack5a">
<center>
<h4>Shopping Cart</h4>
</center>
<table width="90%" cellspacing="0" cellpadding="2" border="1"
align="center">
<tbody>
<tr>
<th width="80%">Shopping Cart Items -- To Buy Now</th>
<th width="10%">Price</th>
<th width="3%">Quantity</th>
<th width="7%">Total</th>
</tr>
<tr>
<td>Studio RTA - Laptop/Reading Cart with Tilting Surface -
Cherry</td>
<td align="right">69.99</td>
<td align="right"><input size="6" value="1" name="QTY1"
type="NUMBER" /></td>
<td>$0.00</td>
</tr>
<tr>
<td>Dynex - Traditional Notebook Case</td>
<td align="right">27.99</td>
<td align="right"><input size="6" value="1" name="QTY2"
type="NUMBER" /></td>
<td>$0.00</td>
</tr>
<tr>
<td>Hewlett-Packard - Pavilion Notebook with Intel Centrino</td>
<td align="right">1599.99</td>
<td align="right"><input size="6" value="1" name="QTY3"
type="NUMBER" /></td>
<td>$0.00</td>
</tr>
<tr>
<td>3 - Year Performance Service Plan $1000 and Over</td>
<td align="right">299.99</td>
<td align="right"><input size="6" value="1" name="QTY4"
type="NUMBER" /></td>
<td>$0.00</td>
</tr>
</tbody>
</table>
<table width="90%" cellspacing="0" cellpadding="2"
align="center">
<tbody>
<tr>
<td>Enter your credit card number:</td>
<td><input name="field1" value="4128 3214 0002 1999"
type="TEXT" /></td>
</tr>
<tr>
<td>Enter your three digit access code:</td>
<td><input name="field2" value="111" type="TEXT" /></td>
</tr>
<br/>
<tr>
<td colspan="3" align="center"><input name="SUBMIT" class="btn btn-primary"
value="Purchase" type="SUBMIT" /></td>
</tr>
</tbody>
</table>
<hr width="90%"/>
</form>
</div>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content5b.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content6.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content6a.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMTestRoute"
action="/WebGoat/CrossSiteScripting/attack6a">
<input name="DOMTestRoute" value="" type="TEXT" />
<input name="SubmitTestRoute" value="Submit" type="SUBMIT"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content6b.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMFollowUp"
action="/WebGoat/CrossSiteScripting/dom-follow-up">
<input name="successMessage" value="" type="TEXT" />
<input name="submitMessage" value="Submit" type="SUBMIT"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<span id="quiz_id" data-quiz_id="cross_site_scripting"></span>
<link rel="stylesheet" type="text/css" th:href="@{/css/quiz.css}"/>
<script th:src="@{/js/quiz.js}" language="JavaScript"></script>
<link rel="import" type="application/json" th:href="@{/lesson_js/questions.json}"/>
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_quiz.adoc"></div>
<div class="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<form id="quiz-form" class="attack-form" accept-charset="UNKNOWN"
method="POST" name="form"
action="/WebGoat/CrossSiteScripting/quiz" role="form">
<div id="q_container"></div>
<br />
<input name="Quiz_solutions" value="Submit answers" type="SUBMIT"/>
</form>
</div>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScriptingMitigation_plan.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content8.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content8a.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content9.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content8b.adoc"></div>
<div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;">
<form id="codesubmit" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack3">
<div>
<div id="editor" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor"></div>
<script th:src="@{/js/libs/ace.js}" type="text/javascript" charset="utf-8"></script>
<script th:src="@{/lesson_js/assignment3.js}" type="text/javascript" charset="utf-8"></script>
</div>
<input type="hidden" name="editor"/>
<div class="input-group" style="position: absolute; top: 365px;">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</form>
<br />
<div class="attack-feedback" style="margin-top: 50px;"></div>
<div class="attack-output"></div>
</div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content8c.adoc"></div>
<div class="attack-container" style="height: 100%; border: none !important;min-height: 450px;">
<form id="codesubmit2" style="height: 100%; min-height: 350px;" class="attack-form" accept-charset="UNKNOWN" method="POST" name="form" action="/WebGoat/CrossSiteScripting/attack4">
<div>
<div id="editor2" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; height: 350px;" name="editor2"></div>
<script th:src="@{/js/libs/ace.js}" type="text/javascript" charset="utf-8"></script>
<script th:src="@{/lesson_js/assignment4.js}" type="text/javascript" charset="utf-8"></script>
</div>
<input type="hidden" name="editor2"/>
<div class="input-group" style="position: absolute; top: 365px;">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</form>
<br />
<div class="attack-feedback" style="margin-top: 50px;"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScriptingStored_plan.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content7.adoc"></div>
</div>
<div class="lesson-page-wrapper">
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content7b.adoc"></div>
<!-- comment area -->
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/stored-xss.css}"/>
<script th:src="@{/lesson_js/stored-xss.js}" language="JavaScript"></script>
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<div class="container-fluid">
<div class="panel post">
<div class="post-heading">
<div class="pull-left image">
<img th:src="@{/images/avatar1.png}"
class="img-circle avatar" alt="user profile image"/>
</div>
<div class="pull-left meta">
<div class="title h5">
<a href="#"><b>John Doe</b></a>
uploaded a photo.
</div>
<h6 class="text-muted time">24 days ago</h6>
</div>
</div>
<div class="post-image">
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
</div>
<div class="post-description">
</div>
<div class="post-footer">
<div class="input-group">
<input class="form-control" id="commentInput" placeholder="Add a comment" type="text"/>
<span class="input-group-addon">
<i id="postComment" class="fa fa-edit" style="font-size: 20px"></i>
</span>
</div>
<ul class="comments-list">
<div id="list">
</div>
</ul>
</div>
</div>
</div>
<!-- end comments -->
<div class="adoc-content" th:replace="doc:lessons/xss/documentation/CrossSiteScripting_content7c.adoc"></div>
<div class="attack-container">
<!-- this will be where they can store the additional comment -->
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST" name="DOMFollowUp"
action="/WebGoat/CrossSiteScripting/stored-xss-follow-up">
<input name="successMessage" value="" type="TEXT" />
<input name="submitMessage" value="Submit" type="SUBMIT"/>
</form>
<div class="attack-feedback"></div>
<div class="attack-output"></div>
</div>
</div>
</html>

View File

@ -0,0 +1,42 @@
# XSS success, failure messages and hints
xss.title=Cross Site Scripting
xss-stored.title=Cross Site Scripting (stored)
xss-mitigation.title=Cross Site Scripting (mitigation)
xss-reflected-5a-success-alert=Congratulations, but alerts are not very impressive are they? Let's continue to the next assignment.
xss-reflected-5a-success-console=Congratulations, but console logs are not very impressive are they? Let's continue to the next assignment.
xss-reflected-5a-failed-wrong-field=Seems like you tried to compromise our shop with an reflected XSS attack.<br/> We do our... "best"... to prevent such attacks. Try again!
xss-reflected-5a-failure=Try again. We do want to see a specific JavaScript mentioned in the goal of the assignment (in case you are trying to do something fancier).
xss-reflected-5a-hint-1=Think about how the inputs are presumably processed by the application.
xss-reflected-5a-hint-2=Quantity inputs are probably processed as integer values. Not the best option for inputting text right?
xss-reflected-5a-hint-3=What information send to the application gets reflected back after being submitted?
xss-reflected-5a-hint-4=Just try purchasing something. You want your script to be included in the purchase-confirmation.
xss-reflected-5b-success=Correct ... because <ul><li>The script was not triggered by the URL/QueryString</li><li>Even if you use the attack URL in a new tab, it will not execute (because of response type). Try it if you like.</li></ul>
xss-reflected-6a-success=Correct! Now, see if you can send in an exploit to that route in the next assignment.
xss-reflected-6a-failure=Sorry that is not correct. Look at the example again to understand what a valid route looks like. If you're stuck... hints might help.
xss-reflected-6a-hint-1=To search through the client side code, use the developer tools of your browser. (If you don't know how to use them, check the <i>Developer Tools</i> Lesson in the general category.)
xss-reflected-6a-hint-2=Since you are looking for application code, check the WebGoat/js/goatApp folder for a file that could handle the routes.
xss-reflected-6a-hint-3=Make sure you add the base route at the start, when submitting your solution.
xss-reflected-6a-hint-4=Still did not find it? Check the <a href="/WebGoat/js/goatApp/view/GoatRouter.js" target="_blank">GoatRouter.js</a> file. It should be pretty easy to determine.
xss.lesson1.failure=The cookies should be the same on both tabs. Ensure that the tabs are from the same site.
xss-dom-message-success=Correct, I hope you did not cheat, using the console!
xss-dom-message-failure=Incorrect, keep trying. It should be obvious in the log when you are successful.
xss-dom-message-hint-1=Open a new tab and navigate to the test-route you just figured out in the previous lesson.
xss-dom-message-hint-2=Your url should look something like that http://localhost:8080/WebGoat/start.mvc#REPLACE-WITH-THE-TEST-ROUTE/some_parameters
xss-dom-message-hint-3=Note how the parameters you send to the test-route get reflected back to the page. Now add your JavaScript to it.
xss-dom-message-hint-4=You have to use script tags, so your JavaScript code gets executed when being rendered into the DOM.
xss-dom-message-hint-5=Since you are working with an URL, you might have to URL-encode your parameters.
xss-dom-message-hint-6=Replace '/' with '%2F' in your URL parameters.
xss-stored-comment-success=It appears your payload should invoke the function. To tell for sure, you need to capture the value and put it in the form below. Then we will really know.
xss-stored-comment-failure=We cannot see the payload in your submission, but XSS can be tricky. Look for the call back fired after the comments reload. If you see that and can put the correct value there and put it in, maybe you did succeed.
xss-stored-callback-success=Yes, that is the correct value (note, it will be a different value each time the phoneHome endpoint is called).
xss-stored-callback-failure=No, that is not the correct value (note, it will be a different value each time the phoneHome endpoint is called).
xss-mitigation-3-hint1=You do not store the user input in this example. Try to encode the user's input right before you place it into the HTML document.
xss-mitigation-3-hint2=Make use of JavaServer Pages Standard Tag Library (JSTL) and JSP Expression Language.
xss-mitigation-3-hint3=Take a look at OWASP Java Encoder Project.
xss-mitigation-3-hint4=Do not forget to reference the tag libs and choose "e" as prefix.
xss-mitigation-3-success=You have completed this lesson. Congratulations!
xss-mitigation-3-failure=This in not the correct answer. Try again!
xss-mitigation-3-no-code=You did not change anything.
xss-mitigation-4-hint1=Try to have a look at the AntiSamy documentation.
xss-mitigation-4-success=You have completed this lesson. Congratulations!
xss-mitigation-4-failed=This is not the correct answer. Try again!

View File

@ -0,0 +1,8 @@
#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.
EnterLastName=Geben Sie Ihren Nachnamen ein:
NoResultsMatched=Keine Resultate gefunden, versuchen Sie es erneut
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"
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
SqlStringInjectionHint4=Try entering [ smith' OR '1' = '1 ].

View File

@ -0,0 +1,8 @@
#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.
EnterLastName=Entrez votre nom :
NoResultsMatched=Aucun r\u00e9sultat correspondant. 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.
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.
SqlStringInjectionHint4=Essayez de saisir [ smith' OR '1' = '1 ].

View File

@ -0,0 +1,8 @@
#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 ].

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,44 @@
$(document).ready( () => {
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.session.setMode("ace/mode/html");
editor.getSession().on("change", () => {
setTimeout( () => {
$("#codesubmit input[name='editor']").val(ace_collect());
}, 20);
});
editor.setValue(
"<html>\n" +
"<head>\n" +
" <title>Using GET and POST Method to Read Form Data</title>\n" +
"</head>\n" +
"<body>\n" +
" <h1>Using POST Method to Read Form Data</h1>\n" +
" <table>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td><b>First Name:</b></td>\n" +
" <td>YOUR CODE HERE</td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td><b>Last Name:</b></td>\n" +
" <td>YOUR CODE HERE</td>\n" +
" </tr>\n" +
" </tbody>\n" +
" </table>\n" +
"</body>\n" +
"</html>\n" +
"\n" +
"\n"
);
});
function ace_collect() {
var editor = ace.edit("editor");
var code = editor.getValue();
return code;
}

View File

@ -0,0 +1,30 @@
$(document).ready( () => {
var editor2 = ace.edit("editor2");
editor2.setTheme("ace/theme/monokai");
editor2.session.setMode("ace/mode/java");
editor2.getSession().on("change", () => {
setTimeout( () => {
$("#codesubmit2 input[name='editor2']").val(ace_collect2());
}, 20);
});
editor2.setValue(
"import org.owasp.validator.html.*;\n" +
"import MyCommentDAO;\n" +
"\n" +
"public class AntiSamyController {\n" +
" public void saveNewComment(int threadID, int userID, String newComment){\n" +
" MyCommentDAO.addComment(threadID, userID, newComment);\n" +
" }\n" +
"}"
);
});
function ace_collect2() {
var editor = ace.edit("editor2");
var code = editor.getValue();
return code;
}

View File

@ -0,0 +1,43 @@
{
"questions": [{
"text": "Are trusted websites immune to XSS attacks?",
"solutions": {
"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.",
"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."
}
}, {
"text": "When do XSS attacks occur?",
"solutions": {
"1": "Data enters a web application through a trusted source.",
"2": "Data enters a browser application through the website.",
"3": "The data is included in dynamic content that is sent to a web user without being validated for malicious content.",
"4": "The data is excluded in static content that way it is sent without being validated."
}
}, {
"text": "What are Stored XSS attacks?",
"solutions": {
"1": "The script is permanently stored on the server and the victim gets the malicious script when requesting information from the server.",
"2": "The script stores itself on the computer of the victim and executes locally the malicious code.",
"3": "The script stores a virus on the computer of the victim. The attacker can perform various actions now.",
"4": "The script is stored in the browser and sends information to the attacker."
}
}, {
"text": "What are Reflected XSS attacks?",
"solutions": {
"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.",
"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."
}
}, {
"text": "Is JavaScript the only way to perform XSS attacks?",
"solutions": {
"1": "Yes you can only make use of tags through JavaScript.",
"2": "Yes otherwise you cannot steal cookies.",
"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."
}
}]
}

View File

@ -0,0 +1,45 @@
$(document).ready(function () {
$("#postComment").on("click", function () {
var commentInput = $("#commentInput").val();
$.ajax({
type: 'POST',
url: 'CrossSiteScripting/stored-xss',
data: JSON.stringify({text: commentInput}),
contentType: "application/json",
dataType: 'json'
}).then(
function () {
getChallenges();
$("#commentInput").val('');
}
)
})
var html = '<li class="comment">' +
'<div class="pull-left">' +
'<img class="avatar" src="images/avatar1.png" alt="avatar"/>' +
'</div>' +
'<div class="comment-body">' +
'<div class="comment-heading">' +
'<h4 class="user">USER</h4>' +
'<h5 class="time">DATETIME</h5>' +
'</div>' +
'<p>COMMENT</p>' +
'</div>' +
'</li>';
getChallenges();
function getChallenges() {
$("#list").empty();
$.get('CrossSiteScripting/stored-xss', function (result, status) {
for (var i = 0; i < result.length; i++) {
var comment = html.replace('USER', result[i].user);
comment = comment.replace('DATETIME', result[i].dateTime);
comment = comment.replace('COMMENT', result[i].text);
$("#list").append(comment);
}
});
}
})