Hey everyone, it's mrzaiazi2k here ๐
As an AI engineer, my primary focus is on models and algorithms. However, working in a bank requires me to understand basic defense mechanisms to secure systems. Today, Iโll be discussing Replay Attacks. I wonโt dive deep into theory; instead, I'll focus on what's fun and interesting about this topic. ๐ฏ
Main Takeaways ๐
- How to perform a replay attack
- Understanding the underlying mechanism
- How to defend against it
How to Perform a Replay Attack
A Replay Attack is a type of network attack where an attacker intercepts valid data transmission and reuses it to perform fraudulent actions or gain unauthorized access to a system. For example, in movies, you might see a thief copying a fingerprint from a lock to gain access. Similarly, in reality, an attacker might copy all parameters and keys from a URL and resend it. Sounds easy, right?
How Can Attackers Capture These Parameters?
Here are two common methods:
1. Man-in-the-Middle (MITM) Attack
What it is:
In a MITM attack, the attacker intercepts communication between a user and a server. This often occurs over an unsecured or poorly secured network, like public Wi-Fi.
How itโs done:
Set Up a Rogue Access Point (AP): The attacker creates a fake Wi-Fi access point with a name similar to a legitimate one (e.g., "CoffeeShop_FreeWiFi"). When the victim connects to this fake AP, all their network traffic can be intercepted.
Intercept Traffic with Wireshark: The attacker uses Wireshark, a network protocol analyzer, on the device hosting the rogue AP. As the victim browses the web, all unencrypted traffic (HTTP) is captured. Even with HTTPS, the attacker can still capture the URLs, although the contents of HTTPS traffic remain encrypted.
Filter and Extract URLs: The attacker filters Wireshark traffic for HTTP GET or POST requests to capture URLs and their parameters. For example, a GET request to
http://example.com/login?username=user&password=pass
would be visible in plain text in Wireshark.Replay or Manipulate the Captured Request: Now, the attacker has the username and password parameters from the captured URL. They can use this information to log in as the user manually or use scripts to automate replay attacks.
2. Browser Developer Tools
What it is:
The attacker tricks the user into clicking a malicious link that appears legitimate, leading to URL parameter theft.
How itโs done:
- Developer Tools: If the attacker gains access to the victim's computer, they can open the browserโs developer tools (usually by pressing F12) and navigate to the "Network" tab. Here, they can inspect all requests the browser makes, including URLs, parameters, and headers.
How to Defend Against Replay Attacks
a. Use Nonces and Timestamps
Nonce (Number Used Once): Use a unique, one-time number to ensure each request is unique and cannot be reused.
Timestamps: Incorporate timestamps to ensure that each request is only valid for a specific time window.
b. Strict Authentication and Authorization
- Use Strong Authentication: Implement strict authentication methods such as JWT (JSON Web Token) or OAuth to verify user identity and control access.
c. Other Defensive Measures:
- Digital Signatures: Generate and validate digital signatures to ensure the integrity and authenticity of requests.
Coding Example
You can find the full source code here.
Signature Validation and Secured API Request Example
Backend (Python/FastAPI):
from functools import wraps
from fastapi import HTTPException, Request
from typing import Callable
from time import time
from hashlib import sha256
import hmac
import redis
NONCE_EXPIRATION_TIME = 60 # seconds
TIMESTAMP_EXPIRATION_TIME = 60 # seconds
SECRET_KEY = "your_secret_key" # Secret key for HMAC
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def validate_nonce(nonce: str):
check_nonce = redis_client.get(nonce)
if check_nonce:
raise HTTPException(status_code=400, detail="Nonce already used")
redis_client.set(nonce, '', ex=NONCE_EXPIRATION_TIME)
def validate_timestamp(timestamp: int):
current_time = int(time())
if abs(current_time - timestamp) > TIMESTAMP_EXPIRATION_TIME:
raise HTTPException(status_code=400, detail="Invalid timestamp")
def generate_signature(secret: str, data: str) -> str:
return hmac.new(secret.encode(), data.encode(), sha256).hexdigest()
def secure_request(f: Callable) -> Callable:
@wraps(f)
async def wrapper(request: Request, *args, **kwargs):
params = request.query_params._dict
print(params)
nonce = params.get("nonce")
timestamp = int(params.get("timestamp"))
signature = params.get("signature")
if not nonce or not timestamp or not signature:
raise HTTPException(status_code=400, detail="Missing required fields")
validate_nonce(nonce)
validate_timestamp(timestamp)
expected_signature = generate_signature(SECRET_KEY, f"{nonce}{timestamp}")
if not hmac.compare_digest(expected_signature, signature):
raise HTTPException(status_code=400, detail="Invalid signature")
return await f(request, *args, **kwargs)
return wrapper
Frontend (HTML/JavaScript):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Secure API Request</title>
</head>
<body>
<button id="fetchUserBtn">Fetch User</button>
<div id="response"></div>
<script>
const SECRET_KEY = 'your_secret_key';
function generateSignature(secret, data) {
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const msgData = encoder.encode(data);
return crypto.subtle.importKey('raw', keyData, {name: 'HMAC', hash: 'SHA-256'}, false, ['sign'])
.then(key => crypto.subtle.sign('HMAC', key, msgData))
.then(signatureBuffer => {
const signatureArray = Array.from(new Uint8Array(signatureBuffer));
return signatureArray.map(b => b.toString(16).padStart(2, '0')).join('');
});
}
async function fetchUser() {
const nonce = Math.random().toString(36).substr(2, 9);
const timestamp = Math.floor(Date.now() / 1000);
const data = nonce + timestamp;
const signature = await generateSignature(SECRET_KEY, data);
const url = `http://127.0.0.1:8000/users?nonce=${nonce}×tamp=${timestamp}&signature=${signature}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
document.getElementById('response').textContent = JSON.stringify(result);
} catch (error) {
console.error('Error fetching user:', error);
document.getElementById('response').textContent = `Error: ${error.message}`;
}
}
document.getElementById('fetchUserBtn').addEventListener('click', fetchUser);
</script>
</body>
</html>
Explanation:
- Nonce Validation: Ensures that each request is unique by storing the nonce in Redis and rejecting any reused nonce.
- Timestamp Validation: Verifies that the request is within a valid time frame, preventing delayed replay attacks.
- Digital Signature: Generates and compares a signature based on the nonce, timestamp, and a secret key, adding an extra layer of security.
- Secure Request Decorator: This decorator wraps the API endpoint to apply the security checks.
Conclusion
Understanding replay attacks and how to defend against them is essential for maintaining secure systems. By implementing the discussed methods, you can protect your applications from such vulnerabilities.
Top comments (1)
In this post, I attempted to find a website to test a replay attack on, but I didnโt have any luck, LOL. Does anyone have any suggestions on how to try a replay attack?