Now that you have identified vulnerabilities in the Unsecure PWA, your next task is to recommend and demonstrate solutions to address them. Your response will be assessed based on how effectively and practically you address the issues.
Choose at least three vulnerabilities from Section 7.
Demonstrate how you would improve the PWA to mitigate each vulnerability, using one of the following approaches:
Exceptional Response: Provide actual code fixes implemented in the Unsecure PWA.
Strong Response: Provide detailed code snippets or samples demonstrating a fix for the issue.
Adequate Response: Provide a clear and detailed explanation of what would need to be done to resolve the issue.
Input validation, sanitisation, and error handling to protect against injection attacks.
Secure authentication and session management practices.
API security, including proper endpoint configurations.
File and user data handling practices to prevent unauthorised access or tampering.
Protection against XSS, CSRF, and other user-action vulnerabilities.
Implementation of security headers (e.g., CSP, HTTPS, CORS).
Mitigating redirects, forwards, and race conditions.
<form action="/submit" method="POST">
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<label for="email">Email:</label>
<input type="text" id="email" name="email">
<button type="submit">Submit</button>
</form>
This form does not include any validation for input fields, making it susceptible to malicious inputs such as cross-site scripting (XSS).
Code Fix Implemented
<form action="/submit" method="POST" onsubmit="return validateForm()">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required pattern="[A-Za-z0-9]{3,20}">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>
<script>
function validateForm() {
const username = document.getElementById('username').value;
const email = document.getElementById('email').value;
const usernameRegex = /^[A-Za-z0-9]{3,20}$/;
if (!usernameRegex.test(username)) {
alert('Invalid username. Use 3-20 alphanumeric characters.');
return false;
}
if (!email.includes('@')) {
alert('Invalid email address.');
return false;
}
return true;
}
</script>
Here, HTML5 input validation (e.g., required, pattern) is combined with JavaScript validation for enhanced security.
Detailed Code Snippet
<form action="/submit" method="POST">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required pattern="[A-Za-z0-9]{3,20}">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>
Explanation: The required attribute ensures the fields cannot be empty, and pattern is used for basic format validation on the username. The type="email" ensures that the email field accepts only valid email formats.
Explanation of Fix To secure this form, input validation should be applied both on the client side and the server side. On the client side:
Use HTML5 validation attributes like required and pattern.
Validate data using JavaScript before submission. On the server side, all inputs must be validated and sanitised to prevent injection attacks, as client-side validation can be bypassed.
from flask import Flask, request
import sqlite3
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
user = cursor.fetchone()
if user:
return "Login successful"
else:
return "Login failed"
This code is vulnerable to SQL Injection due to the direct use of user input in the SQL query.
Code Fix Implemented
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
user = cursor.fetchone()
if user:
return "Login successful"
else:
return "Login failed"
Explanation: The code uses parameterised queries (?) to prevent SQL Injection by ensuring that user inputs are treated as data rather than executable SQL.
Detailed Code Snippet
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
Explanation: Parameterised queries are used to handle user inputs securely. This eliminates the possibility of SQL Injection by separating query logic from data.
The vulnerability can be mitigated by:
Using parameterised queries or prepared statements, which safely handle user inputs.
Avoiding direct concatenation of user inputs into SQL queries.
Implementing additional measures such as hashing passwords instead of storing them in plaintext.