
Gegenprüfen Sie die Ansichten Ihrer Angriffsfläche und finden Sie die Endpunkte, die sich nicht gegenseitig bestätigen können.
Gleiche die Ansichten deiner Angriffsoberfläche gegeneinander ab und finde die Endpunkte, die sich nicht gegenseitig bestätigen können.
Ein Endpunkt sollte für sich selbst Rechenschaft ablegen können. Er steht im Code, also sollte ein Vertrag ihn beschreiben. Er steht im Vertrag, also sollte etwas ihn implementieren. Er empfängt echten Traffic, also sollte er besser irgendwo existieren. Wenn eine Ansicht von einem Endpunkt weiß und die anderen nicht, ist diese Lücke der Befund.
alibi führt OWASP noir aus, liest dessen JSON und vergleicht die Ansichten miteinander.
Noir liest bereits fünf unabhängige Ansichten derselben Oberfläche:
| Ansicht | Gelesen aus |
|---|---|
| code | über 200 Analyzer in 33 Sprachen |
| 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 und Gateway API |
| infra | Terraform, CloudFormation, CDK, Serverless, Vercel, Netlify, Wrangler, Azure Functions, Kamal |
Was es nicht tut, ist sie zu vergleichen. Genau das ist die Aufgabe hier, und sie erfordert keine Änderung an noir — alibi führt es einmal pro Ansicht aus und verknüpft die Ergebnisse.
Der Teil pro Ansicht ist wichtig. Noir dedupliziert nach (method, url) über alle Analyzer hinweg, sodass eine Flask-Route und ein identisch geschriebener OpenAPI-Pfad zu einem einzigen Endpunkt verschmelzen, der eine einzige Technologie trägt. Das ist richtig für ein Discovery-Tool — es ist ein Endpunkt —, aber es löscht die Bestätigung aus, die dieses Tool messen soll, und es löscht sie in der denkbar schlechtesten Richtung: Je besser zwei Ansichten übereinstimmen, desto mehr von ihnen verschwinden. Casdoor wird als 372 Code-Endpunkte und 9 dokumentierte gescannt; scannt man allein sein swagger/-Verzeichnis, hat die Spezifikation 235.
--only-techs schränkt den Detektor-Pool ein, sodass ein Scan pro Ansicht jede einzelne vollständig hält. Welche Technologie für welche Ansicht spricht, steht in views.yml; welche Technologien existieren, ist das, was noir list techs meldet.
alibi parst keine API-Formate aus eigener Kraft. Seine einzige Eingabe ist das JSON von noir.
Erfordert noir 1.0.0 oder neuer im PATH -- das ist die Version, in der noir list techs zu einem Unterbefehl wurde, und dieser Katalog ist es, der jede Technologie einer Ansicht zuweist. Die Entwicklung folgt der aktuellen noir-Version. Eine ältere Binary wird namentlich abgelehnt, statt beim ersten Kataloglesen zu scheitern.
$ 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
Jeder Pfad ist eine Quelle und wird einmal pro Ansicht gescannt. Richte ihn auf das, was du hast — einen Quellbaum, ein Spezifikationsverzeichnis, eine einzelne Capture-Datei — und die Ansichten, die dir fehlen, schalten ihre Regeln ab, statt den Bericht zu überfluten.
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.
Gruppen enden bei zwölf — die Reihenfolge ist worst-first, sodass der Rest der am wenigsten informative Teil ist, und -f json enthält alles davon.
Flags für noir werden nach einem bloßen -- oder über --noir-arg angegeben. Filter wie --exclude-path sind in Ordnung; Flags, die den JSON-Vertrag ersetzen oder die per-View-Scans von alibi zusammenfassen würden (--format, --diff-*, --only-techs, …), werden mit Exit-Status 2 abgelehnt.
- run: alibi scan . ./contracts -f sarif > alibi.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: alibi.sarif }
Der Bericht besagt, dass die Ansichten nicht übereinstimmen; --endpoints gibt an, was jede von ihnen
enthielt.
$ alibi scan ./repo -f json --endpoints
Jede Ansicht erhält eine Liste: den Schlüssel, welche Ansichten ihn bestätigt haben, die dahinterstehenden Technologien, die Dateien und die Schreibweise vor der Normalisierung – genau dort liegt immer der Unterschied, wenn zwei Zeilen hätten übereinstimmen sollen und es nicht taten. Das ist drei- bis viermal so viel wie der Rest der Nutzlast, daher ist es ein Flag und nicht der Standard.
Oder direkt als Gate: alibi scan . ./contracts --fail-on high beendet sich mit einem Nicht-Null-Exit-Code, wenn ein Fund diesen Schweregrad erreicht. Ein Scan, den noir nicht vollständig lesen konnte, meldet executionSuccessful: false, sodass ein beeinträchtigter Lauf nicht als sauberer Lauf durchgeht. Ein Symlink, eine Binärdatei oder ein Image, das noir absichtlich übersprungen hat, zählt nicht.
Noir behält die eigene Routensyntax jedes Frameworks bei, anstatt eine gemeinsame zu erfinden, sodass derselbe Endpunkt in mehreren Schreibweisen ankommt:
python_flask /api/users/<int:user_id>
aiohttp /users/{id}
java_spring /api/catalog/{id}
oas3 /v1/pets/{petId}
rails /posts/:id
nginx /admin/.*
Die Regel, die diese vergleichbar macht: Der Name eines Pfadparameters ist nicht Teil seiner Identität. {petId} und <int:user_id> beschreiben denselben Slot; nur seine Position und ob er ein / überspannt, zählen. Namen werden als Beleg aufbewahrt und berichtet, erreichen aber niemals den Schlüssel.
Die Befunde geben an, wie die Übereinstimmung zustande kam:
| Grad | Bedeutung |
|---|---|
G1 | die Schreibweisen stimmten bereits überein |
G2 | sie stimmen überein, sobald die Parametersyntax normalisiert ist |
G0 | nur eine Ansicht enthält ihn — nichts wurde abgeglichen |
Ein Werkzeug wie dieses stirbt daran, dass es beim ersten Lauf Hunderte von Befunden meldet oder Fortschritt meldet, den niemand gemacht hat. Sechs Dinge wirken dem entgegen:
Regeln feuern nicht ohne beide Ansichten. Durchsuche eine Codebasis ohne irgendwo Contracts, und jeder Endpunkt qualifiziert sich technisch als undokumentierte Shadow-API. Diese Befunde sagen nichts aus außer, dass du keine Dokumentation geliefert hast, daher läuft eine Regel nur, wenn jede Ansicht, über die sie schließt, tatsächlich im Scan enthalten war. Der Bericht nennt die Regeln, die ausgesetzt haben.