**Security Flaws Identification and Solution**
*Written by Laquinta, Ochea, Tan*
---
Web applications are susceptible to various vulnerabilities that can compromise their security and integrity. SQL Injection (SQLi) occurs when attackers manipulate SQL queries, potentially accessing or modifying sensitive data. Cross-Site Scripting (XSS) enables attackers to inject malicious scripts into web pages, compromising user sessions or redirecting them to harmful sites. Cross-Site Request Forgery (CSRF) tricks users into executing unintended actions on authenticated web applications.
*Now, How do we protect our web applications from these attacks?*
---
**SQL Injection:**
The website is vulnerable to SQL Injection as shown in the provided pictures, specifically in the login page. The vulnerability lies in how the user inputs are directly concatenated into the SQL query string without any sort of parameterizations.
```python
res = cur.execute("SELECT id from users WHERE username = '"
+ request.form["username"]
+ "' AND password = '"
+ request.form["password"] + "'")
user = res.fetchone()
```
This allows potential attackers to directly manipulate and tamper with the SQL query which can result in the pictures shown below.


As shown above, we can input a condition in the text that would result to true which would allow us access to the home page. The two dashes after the condition is a comment statement that would comment out the request query for the password, thereby bypassing the need of a correct password.

And now we're in, and as the attackers we can do whatever malicious actions we are intending to do without the consent of the original user.
**Solution:**
The flaw is solved by implementing a simple parameterized query. In this case, the placeholders '?' are used in the SQL statement instead of the actual values in the input fields.
```python
username = request.form["username"]
password = request.form["password"]
query = "SELECT id FROM users WHERE username = ? AND password = ?"
res = cur.execute(query, (username, password))
user = res.fetchone()
```
This approach is safe from SQL Injection as it separates the SQL command from the data itself. This makes it so that even if the attacker attempts to input malicious SQL code into the input fields, it will be treated as data rather than an executable SQL code.
**Accesing User Credentials through POST:**
By posting this particular text in the input field for post, we can gain access to the credentials of all users registered in the database:
```sql
1' , 1), ((SELECT GROUP_CONCAT(id || ',' || username || ':' || password, '<br>') FROM users), 1) --
```
This is a combination of SQL Injection as well as an XSS attack which would result in the image shown below:

**Solution:**
Similar to the solution for SQL Injection, we can fix this flaw by simply implementing a simple parameterized query.
From this,
```python
def posts():
cur = con.cursor()
if request.cookies.get("session_token"):
res = cur.execute("SELECT users.id, username FROM users INNER JOIN sessions ON "
+ "users.id = sessions.user WHERE sessions.token = '"
+ request.cookies.get("session_token") + "';")
user = res.fetchone()
if user:
cur.execute("INSERT INTO posts (message, user) VALUES ('"
+ request.form["message"] + "', " + str(user[0]) + ");")
con.commit()
return redirect("/home")
return redirect("/login", error="test")
```
To this,
```python
def posts():
cur = con.cursor()
if request.cookies.get("session_token"):
res = cur.execute("SELECT users.id, username FROM users INNER JOIN sessions ON "
+ "users.id = sessions.user WHERE sessions.token = '"
+ request.cookies.get("session_token") + "';")
user = res.fetchone()
if user:
cur.execute("INSERT INTO posts (message, user) VALUES (?, ?);", (request.form["message"], user[0]))
con.commit()
return redirect("/home")
return redirect("/login", error="test")
```
And now when we try to access the user credentials through the input field, instead of receiving a response from an SQL query, we instead get the input text.

---
**Cross-Site Request Forgery (CSRF):**
Shown below is a malicious HTML page that can be used to trick the user to perform unintended actions. In this case, the user is tricked to post a message by the attacker.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Malicious Post</title>
</head>
<body>
<!-- Perform CSRF attack to create a new post -->
<form id="csrfPostForm" action="http://localhost:5000/posts" method="POST">
<input type="hidden" name="message" value="You have been hacked ᕦ(ò_óˇ)">
<input type="submit" value="Create Post">
</form>
<!-- Automatically submits the form when the page loads -->
<script>
document.getElementById("csrfPostForm").submit();
</script>
</body>
</html>
```
Once the user is tricked to open the html file either through social engineering, a phishing email, or any other methods, the user's browser automatically submits the form, creating a new post with the malicious content without their consent. Shown below is the result of the user visiting the HTML page:

**Solution:**
We can resolve this issue by simply implementing the use of CSRF tokens. A CSRF token is generated through the following code:
```python
csrf_token = secrets.token_urlsafe(16)
...
response = make_response(render_template("home.html", username=user[1], posts=posts, csrf_token=csrf_token))
response.set_cookie("csrf_token", csrf_token, httponly=True)
return response
```
In the home page, the form for the post will also make use of the CSRF token. We include the CSRF token as a hidden value as follows:
```html
<form method="post" action="/posts">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}" />
<input type="text" name="message">
<input type="submit" value="Post!">
</form>
```
A validate_csrf() function was also created to verify that both CSRF tokens are the same before a post is submitted and posted. The code is as follows:
```python
def validate_csrf():
if request.form.get("csrf_token") == request.cookies.get("csrf_token"):
return True
else:
return False
```
This prevents posting from a different source and only allows posting that comes from the actual home page. This is how it looks like if someone tries to post from a malicious HTML page:

It will show an internal server error and the post attempt will not go through.
---
**XSS:**
Another vulnerability is XSS attacked (Cross-site Scripting) which basically allows attackers to inject malicious scripts into a benign, trusted website.

Attackers can inject malicious code in the "Posts" feature of the website since it does not validate the inputs. We can create an alert (which creates a pop-up on the website) which is quite a simple attack for now. However, attackers of higher level may be able to inject a more evil script which may possibly harm the website and inconvenience or harm its users.
Here is an example of an XSS attack. The script inserted in the input field is as follows:
```html
<script>alert("This is an XSS attack! :P")</script>
```
Here is how it looks like:

**Solution:**
The solution for preventing XSS attacks is sanitizing the input text. Based on the attack above, we used \<script> tag which is an HTML element. The input text is interpreted as a script that is part of the actual code when, in fact, it is not. That is where sanitization comes in. The utilizing 'escape' from the MarkupSafe library, we can create a sanitizer function such as the following:
```python
from markupsafe import escape
def sanitize(message):
return escape(message)
```
This is a very simple sanitizer function which takes the message as input and converts some symbols to their entity name, such as '<' becoming '\<' and '>' becoming '\>.' This allows the text to be posted on the Posts section of the homepage without being interpreted as a script.
Here is how it looks like after 'posting' a script in the Posts section:

---
**Bruteforce:**
The application does not employ any bruteforce protection measures. With BurpSuite, the application is vulnerable to bruteforcing.
Tools:
1. BurpSuite's Intruder
2. Two payloads (for username and password positions)
<img src="https://hackmd.io/_uploads/BJplHd3MA.png" alt="Image" style="border: 1px solid black;">
<!--  -->
Use the two payloads with the **Clusterbomb** mode on BurpSuite's Intruder. The **Clusterbomb** mode tries every permutation of payload combination. Notice that for most requests, the status code is 200 with response length of 593. Any change with the status code or length from the general data can be worth checking. It can be observed that when tried with the correct username and password, the status code and length of the response changes drastically.
<img src="https://hackmd.io/_uploads/Bk2phd2MA.png" alt="Image" style="border: 1px solid black;">
<!--  -->
**Solution:**
This vulnerability can be solved by employing the following countermeasure. Flask has **Flask-Limiter** extension that can prevent further requests given a certain amount and timeframe which is effective in hindering bruteforce attacks. A basic implementation to the login() route is the folowing:
```python
import secrets
import sqlite3
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask import Flask, request, render_template, redirect
app = Flask(__name__)
con = sqlite3.connect("app.db", check_same_thread=False)
limiter = Limiter(
get_remote_address,
app=app,
default_limits=["200 per day", "50 per hour"],
storage_uri="memory://",
)
@app.route("/login", methods=["GET", "POST"])
@limiter.limit("50 per day")
def login():
```
In effect, we can see the situation where the requests go beyond the threshold by analyzing the corresponding responses. The status code changes into 429 (customized status code set by the Flask extension) when requests go beyond the rate limit and essentially cripples any further login attempts.
<img src="https://hackmd.io/_uploads/HkCuDY3z0.png" alt="Image" style="border: 1px solid black;">
Any requests made beyond the current rate limit displays the following:
<img src="https://hackmd.io/_uploads/Hk5aek6GC.png" alt="Image" style="border: 1px solid black;">
**References:**
https://owasp.org/www-community/attacks/xss/