Intermediate Web — OWASP Top 10

SSRF — Accessing Internal Services Through the Server

Server-Side Request Forgery (SSRF) occurs when an application accepts a user-controlled URL and makes an HTTP request to it from the server itself. The attacker uses the server as a proxy to reach internal networks that are otherwise inaccessible.

Basic Scenario

Legitimate feature: "Fetch URL preview for sharing"
Parameter: POST /preview?url=https://news.example.com/article

Exploitation: POST /preview?url=http://192.168.1.1/admin
The server makes the request internally and returns the response to the attacker.

SSRF in Cloud Environments — Metadata Endpoint

In AWS, every server has access to the instance metadata endpoint:

http://169.254.169.254/latest/meta-data/iam/security-credentials/

A successful SSRF against this endpoint leaks the temporary IAM credentials of the role attached to the instance — full AWS account compromise.

Attack:
POST /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/prod-role

Response:
{
  "AccessKeyId": "ASIA...",
  "SecretAccessKey": "...",
  "Token": "..."
}

GCP and Azure have similar endpoints.

Bypassing Naive Validations

// String-based blocklist — easily bypassed
Blocked:  http://localhost/
Bypass:   http://0.0.0.0/
Bypass:   http://[::1]/
Bypass:   http://127.0.0.1.nip.io/   (resolves to 127.0.0.1)
Bypass:   http://0177.0.0.1/         (octal)
Bypass:   http://2130706433/         (decimal)

Protocols Beyond HTTP

file:///etc/passwd        — reads local file
gopher://internal:25/...  — interacts with internal SMTP
dict://internal:6379/     — accesses passwordless Redis

Prevention

1. Host/IP Allowlist

ALLOWED_HOSTS = {'api.partner.com', 'cdn.example.com'}

from urllib.parse import urlparse
parsed = urlparse(user_url)
if parsed.hostname not in ALLOWED_HOSTS:
    raise ValueError("Host not permitted")

2. Block Private Ranges After DNS Resolution

import socket, ipaddress

ip = socket.gethostbyname(hostname)
addr = ipaddress.ip_address(ip)
if addr.is_private or addr.is_loopback or addr.is_link_local:
    raise ValueError("Private address not permitted")

3. Network Segmentation

Application servers should not have direct access to the internal admin network. Egress firewall blocking 169.254.169.254 and 10.0.0.0/8 from the application process.

4. IMDSv2 on AWS

aws ec2 modify-instance-metadata-options \
  --http-tokens required \
  --instance-id i-xxxx

IMDSv2 requires a token header — a simple SSRF request can no longer fetch credentials.

5. Least Privilege

IAM Roles with minimal permissions limit damage if credentials are exposed.