
Verifica in modo incrociato le viste della tua superficie di attacco e individua gli endpoint che non possono corroborarsi a vicenda.
Verifica in modo incrociato le viste della tua superficie di attacco e trova gli endpoint che non possono confermarsi a vicenda.
Un endpoint dovrebbe essere in grado di giustificare se stesso. È nel codice, quindi un contratto dovrebbe descriverlo. È nel contratto, quindi qualcosa dovrebbe implementarlo. Riceve traffico reale, quindi farebbe meglio a esistere da qualche parte. Quando una vista conosce un endpoint e le altre no, quella lacuna è il risultato.
alibi esegue OWASP noir, legge il suo JSON e confronta le viste tra loro.
Noir legge già cinque viste indipendenti della stessa superficie:
| Vista | Letta da |
|---|---|
| code | oltre 200 analizzatori in 33 linguaggi |
| doc | OpenAPI, RAML, WSDL, GraphQL SDL, AsyncAPI, gRPC, Smithy, TypeSpec, OData, OpenRPC |
| traffic | HAR, mitmproxy, Burp, Caido, ZAP, Postman, Insomnia, Bruno, .http |
| gateway | nginx, Apache, Envoy, Kong, Traefik, APISIX, Caddy, Istio, Kubernetes Ingress e Gateway API |
| infra | Terraform, CloudFormation, CDK, Serverless, Vercel, Netlify, Wrangler, Azure Functions, Kamal |
Ciò che non fa è confrontarle. Questo è l'intero compito qui, e non richiede alcuna modifica a noir — alibi lo esegue una volta per vista e unisce i risultati.
La parte per-vista è importante. Noir deduplica per (method, url) attraverso ogni
analizzatore, quindi una route Flask e un path OpenAPI scritti in modo identico collassano in
un unico endpoint che porta una sola tecnologia. Questo è corretto per uno strumento di discovery — è
un endpoint — ma cancella la corroborazione che questo strumento è costruito per misurare,
e la cancella nella peggiore direzione possibile: più due viste concordano,
più di esse svaniscono. Casdoor viene scansionato come 372 endpoint di codice e 9 documentati;
scansiona solo la sua directory swagger/ e la specifica ne ha 235.
--only-techs limita il pool di rilevatori, quindi una scansione per vista mantiene ciascuna
integra. Quale tecnologia parla per quale vista è views.yml; quali
tecnologie esistono è ciò che riporta noir list techs.
alibi non analizza alcun formato API per conto proprio. Il suo unico input è il JSON di noir.
Richiede noir 1.0.0 o superiore nel
PATH -- è la release in cui noir list techs è diventato un sottocomando, e
quel catalogo è ciò che assegna ogni tecnologia a una vista. Lo sviluppo segue la
release corrente di noir. Un binario più vecchio viene rifiutato per nome anziché essere lasciato
fallire alla sua prima lettura del catalogo.
$ uv tool install noir-alibi # or: pipx install noir-alibi
$ alibi scan ./my-service
$ alibi scan # the working directory
$ alibi scan ./service ./contracts ./prod.har # or wherever the views live
Ogni path è una sorgente, scansionata una volta per vista. Puntalo su ciò che hai — un albero di codice sorgente, una directory di specifiche, un singolo file di cattura — e le viste che mancano disattivano le loro regole anziché inondare il report.
alibi · 1 source · 377 endpoints
code 372 doc 235
230 corroborated -- vouched for by more than one view
19 endpoints nearly matched another view -- these may be matching failures, not real gaps
SHADOW Shadow API -- Implemented, but no contract describes it
134 findings · 4 critical, 57 high, 62 medium, 11 low
critical POST /api/upload-groups router.go:87
upload paths carry more consequence than reads
critical POST /api/upload-permissions router.go:208
...
... and 122 more (SHADOW in full: -f json)
TWO SURFACES?
The doc view is 97% under /api, and 37 of these findings are outside it.
If that is a separate surface the contract never covered, narrow the scan:
alibi scan <paths> --ignore '^/(?!api(/|$))'
If it is the same surface left undocumented, they are the findings that matter most.
I gruppi si fermano a dodici — l'ordinamento è dal peggiore al migliore, quindi la coda è la parte meno
informativa, e -f json ha tutto.
I flag per noir vanno dopo un -- nudo o tramite --noir-arg. Filtri come
--exclude-path vanno bene; i flag che sostituirebbero il contratto JSON o
collasserebbero le scansioni per-vista di alibi (--format, --diff-*, --only-techs, …)
vengono rifiutati con stato di uscita 2.
- run: alibi scan . ./contracts -f sarif > alibi.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: alibi.sarif }
Il report dice che le viste non concordano; --endpoints dice cosa ciascuna di esse
conteneva.
$ alibi scan ./repo -f json --endpoints
Ogni vista ottiene una lista: la chiave, quali viste l'hanno confermata, le tecnologie dietro di essa, i file, e la scrittura prima della normalizzazione — che è dove si trova sempre la differenza quando due righe avrebbero dovuto corrispondere e non l'hanno fatto. È da tre a quattro volte il resto del payload, quindi è un flag anziché il default.
Oppure applica direttamente una soglia: alibi scan . ./contracts --fail-on high esce con codice diverso da zero quando
un risultato raggiunge quella severità. Una scansione che noir non ha potuto leggere per intero riporta
executionSuccessful: false, quindi un'esecuzione degradata non passa come una pulita.
Noir mantiene la sintassi delle route propria di ciascun framework anziché inventarne una comune, quindi lo stesso endpoint arriva scritto in diversi modi:
python_flask /api/users/<int:user_id>
aiohttp /users/{id}
java_spring /api/catalog/{id}
oas3 /v1/pets/{petId}
rails /posts/:id
nginx /admin/.*
La regola che li rende confrontabili: il nome di un parametro di path non fa parte della
sua identità. {petId} e <int:user_id> descrivono lo stesso slot; contano solo la sua
posizione e se attraversa un /. I nomi sono conservati come evidenza e
riportati, ma non raggiungono mai la chiave.
I risultati dicono come è stata fatta la corrispondenza:
| Grado | Significato |
|---|---|
G1 | le scritture concordavano già |
G2 | concordano una volta normalizzata la sintassi dei parametri |
G0 | solo una vista ce l'ha — nulla è stato confrontato |
Uno strumento come questo muore riportando centinaia di risultati alla sua prima esecuzione, o riportando progressi che nessuno ha fatto. Sei cose spingono in senso contrario:
Le regole non scattano senza entrambe le viste. Scansiona una codebase senza contratti da nessuna parte e ogni endpoint tecnicamente si qualifica come una shadow API non documentata. Quei risultati non dicono nulla se non che non hai fornito alcuna documentazione, quindi una regola viene eseguita solo quando ogni vista su cui ragiona era effettivamente nella scansione. Il report nomina le regole che sono rimaste fuori.
I quasi-match sono riportati come dubbio, non come risultati. "Nel codice, non nella documentazione" è indistinguibile da "in entrambi, ma alibi non è riuscito ad allinearli." Quindi un endpoint che finisce in una vista viene controllato rispetto alle altre per un quasi match — stesso path con un verbo diverso, o a un segmento di distanza dove un lato ha un parametro e l'altro un letterale. I risultati che portano un quasi-match sono declassati e segnalati per revisione. Quel conteggio sta accanto ai totali, perché ogni risultato è affidabile solo quanto è piccolo.