Web applications are critical to modern business, enabling everything from e-commerce platforms to social networks. However, with this widespread use comes a growing threat landscape. Web application attacks target vulnerabilities in these applications and can have devastating consequences for organizations and users alike. In this blog post, we will explore the most common web application attacks, how they work, and how you can defend against them.
Web application attacks exploit weaknesses in web applications—software applications accessed via a web browser. They can occur at various layers of the application stack, including the application code, web server, and database. These attacks can range from simple manipulations of input fields to complex exploits that compromise an entire system.
Web application vulnerabilities are often the result of poor coding practices, misconfigurations, or inadequate security measures. Understanding the types of web application attacks is critical to safeguarding both the application and its users.
SQL Injection (SQLi) occurs when an attacker manipulates an application's database query to gain unauthorized access to data. By injecting malicious SQL code into an input field (like a login form or search bar), the attacker can bypass authentication or retrieve, modify, or delete data from the database.
An attacker might enter something like ' OR 1=1 --
in a username field. If the input is not properly sanitized, the application might run a query such as:
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = 'password';
This query would always return true because 1=1
is always true, allowing the attacker to log in without a password.
import sqlite3
def login(username, password):
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
# Using parameterized queries to prevent SQL Injection
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
user = cursor.fetchone()
if user:
print("Login successful!")
else:
print("Invalid credentials")
conn.close()
# Example usage
login('admin', 'password123')
Cross-Site Scripting (XSS) is an attack where attackers inject malicious scripts (usually JavaScript) into webpages viewed by other users. The goal is to steal session cookies, hijack user sessions, or perform other malicious activities in the victim’s browser.
An attacker might inject a malicious JavaScript payload into an input field, such as a comment section. When another user views the page, the script executes in their browser. For instance, the attacker could inject the following:
<script>alert('XSS Attack!');</script>
This could execute in the victim’s browser, leading to stolen credentials or sensitive data.
HTTPOnly
to make them inaccessible to JavaScript.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS Prevention Example</title>
</head>
<body>
<form id="comment-form">
<textarea id="comment" placeholder="Enter your comment"></textarea>
<button type="submit">Submit</button>
</form>
<div id="comments-section"></div>
<script>
// Function to sanitize input before rendering
function sanitizeInput(input) {
var element = document.createElement('div');
element.innerText = input; // Escapes any HTML/JS content
return element.innerHTML;
}
document.getElementById('comment-form').addEventListener('submit', function(event) {
event.preventDefault();
var comment = document.getElementById('comment').value;
var sanitizedComment = sanitizeInput(comment);
document.getElementById('comments-section').innerHTML += `<p>${sanitizedComment}</p>`;
});
</script>
</body>
</html>
Cross-Site Request Forgery (CSRF) is an attack where an attacker tricks a user into performing unwanted actions on a web application in which they are authenticated. The attacker can exploit the user's session to perform actions on their behalf without their consent, like changing account settings or making transactions.
Imagine a user is logged into their bank account. If they visit a malicious website while still logged in, the website can send a request (such as transferring funds) to the bank’s server, using the victim’s session credentials. Since the user is authenticated, the request is processed as legitimate.
SameSite
cookie attribute to restrict cross-site requests.Referer
header of incoming requests matches the expected domain.
from flask import Flask, request, session, redirect, url_for
import secrets
app = Flask(__name__)
app.secret_key = 'supersecretkey'
# Generate CSRF token for form submission
def generate_csrf_token():
token = secrets.token_hex(16)
session['csrf_token'] = token
return token
@app.route('/form', methods=['GET', 'POST'])
def form():
if request.method == 'POST':
# Validate CSRF token
csrf_token = request.form.get('csrf_token')
if csrf_token != session.get('csrf_token'):
return "CSRF token is missing or incorrect", 400
# Process the form here
return "Form submitted successfully"
return '''
<form method="post">
<input type="text" name="data">
<input type="hidden" name="csrf_token" value="{}">
<button type="submit">Submit</button>
</form>
'''.format(generate_csrf_token())
if __name__ == '__main__':
app.run(debug=True)
Explanation:
In this Flask example, we generate a unique CSRF token for each session, which is included in the form as a hidden field. The server checks the token during form submission to ensure the request is legitimate.
Command injection occurs when an attacker is able to execute arbitrary commands on a server by injecting malicious input into a vulnerable system. This can lead to the compromise of the system’s security and sensitive data.
If an application takes user input and uses it in system commands (like shell commands) without proper validation, attackers can inject malicious commands. For example:
import os
def delete_user(username):
os.system(f"rm -rf /home/{username}")
delete_user("victim; rm -rf /") # Malicious command
In this example, an attacker could delete all files on the server by injecting a malicious command.
os.system
) with user input. Instead, use safer alternatives.
import subprocess
def delete_user(username):
# Use subprocess with arguments to avoid command injection
subprocess.run(['rm', '-rf', f'/home/{username}'], check=True)
delete_user("victim") # Safe command execution
Explanation:
By passing user input as separate arguments to subprocess.run()
, we prevent command injection, as the user input is not directly executed in the shell.
File upload vulnerabilities occur when an attacker uploads malicious files to a server, which can then be executed or used to compromise the server.
An attacker may upload a file containing a malicious script or a backdoor that the server inadvertently executes. For example, uploading a .php
or .exe
file disguised as an image.
.jpg
or .png
) can be uploaded.
import os
from werkzeug.utils import secure_filename
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def upload_file(file):
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join('/path/to/uploads', filename))
return "File uploaded successfully"
else:
return "Invalid file type"
# Example usage
upload_file(uploaded_file)
Explanation:
In this example, the file type is checked to ensure it’s one of the allowed image formats. The secure_filename()
function prevents directory traversal and other common file-based attacks.