
Faça uma verificação cruzada das visualizações da sua superfície de ataque e encontre os endpoints que não conseguem corroborar uns com os outros.
Faça a verificação cruzada das visões da sua superfície de ataque e encontre os endpoints que não conseguem se corroborar mutuamente.
Um endpoint deveria ser capaz de responder por si mesmo. Ele está no código, então um contrato deveria descrevê-lo. Ele está no contrato, então algo deveria implementá-lo. Ele recebe tráfego real, então é melhor que exista em algum lugar. Quando uma visão conhece um endpoint e as outras não, essa lacuna é o achado.
alibi executa o OWASP noir, lê seu JSON e compara as visões entre si.
O Noir já lê cinco visões independentes da mesma superfície:
| Visão | Lida de |
|---|---|
| code | mais de 200 analisadores em 33 linguagens |
| 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 |
O que ele não faz é compará-las. Esse é o trabalho inteiro aqui, e não requer nenhuma alteração no noir — o alibi o executa uma vez por visão e une os resultados.
A parte por visão importa. O Noir deduplica por (method, url) em todos os
analisadores, então uma rota Flask e um caminho OpenAPI escritos de forma idêntica colapsam em
um único endpoint carregando uma única tecnologia. Isso é correto para uma ferramenta de descoberta — é
um endpoint — mas apaga a corroboração que esta ferramenta foi feita para medir,
e a apaga na pior direção possível: quanto melhor duas visões concordam,
mais delas desaparecem. O Casdoor é escaneado como 372 endpoints de código e 9 documentados;
escaneie apenas seu diretório swagger/ e a especificação terá 235.
--only-techs restringe o conjunto de detectores, então um scan por visão mantém cada uma
inteira. Qual tecnologia responde por qual visão é definido em views.yml; quais
tecnologias existem é o que noir list techs reportar.
O alibi não analisa nenhum formato de API por conta própria. Sua única entrada é o JSON do noir.
Requer o noir 1.0.0 ou mais recente no
PATH -- essa é a versão em que noir list techs se tornou um subcomando, e
esse catálogo é o que atribui cada tecnologia a uma visão. O desenvolvimento acompanha a
versão atual do noir. Um binário mais antigo é recusado pelo nome em vez de ser deixado para
falhar na sua primeira leitura de catálogo.
$ 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
Todo caminho é uma fonte, escaneada uma vez por visão. Aponte-o para o que você tiver — uma árvore de código-fonte, um diretório de especificação, um único arquivo de captura — e as visões que estão faltando desativam suas regras em vez de inundar o relatório.
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.
Os grupos param em doze — a ordenação é do pior para o melhor, então a cauda é a parte menos informativa, e -f json tem tudo.
As flags para o noir vão depois de um -- isolado ou através de --noir-arg. Filtros como --exclude-path são permitidos; flags que substituiriam o contrato JSON ou colapsariam as varreduras por view do alibi (--format, --diff-*, --only-techs, …) são recusadas com status de saída 2.
- run: alibi scan . ./contracts -f sarif > alibi.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: alibi.sarif }
O relatório indica que as views divergem; --endpoints mostra o que cada uma delas
continha.
$ alibi scan ./repo -f json --endpoints
Cada view recebe uma lista: a chave, quais views a validaram, as tecnologias por trás dela, os arquivos e a grafia antes da normalização — que é onde a diferença sempre está quando duas linhas deveriam ter correspondido e não corresponderam. É de três a quatro vezes o restante do payload, então é um flag em vez do padrão.
Ou faça o gate diretamente: alibi scan . ./contracts --fail-on high sai com código
diferente de zero quando um achado atinge essa severidade. Uma varredura que o noir não conseguiu
ler por completo reporta executionSuccessful: false, então uma execução degradada não passa como uma limpa.
Um symlink, binário ou imagem que o noir ignorou de propósito não conta.
O Noir mantém a sintaxe de rota própria de cada framework em vez de inventar uma comum, então o mesmo endpoint chega escrito de várias formas:
python_flask /api/users/<int:user_id>
aiohttp /users/{id}
java_spring /api/catalog/{id}
oas3 /v1/pets/{petId}
rails /posts/:id
nginx /admin/.*
A regra que torna esses casos comparáveis: o nome de um parâmetro de caminho não faz parte da sua identidade. {petId} e <int:user_id> descrevem o mesmo slot; apenas a sua posição e se ele abrange um / importam. Os nomes são mantidos como evidência e reportados, mas nunca chegam à chave.
Os achados indicam como a correspondência foi feita:
| Grau | Significado |
|---|---|
G1 | as grafias já coincidiam |
G2 | coincidem após a normalização da sintaxe de parâmetros |
G0 | apenas uma visão o possui — nada foi correspondido |
Uma ferramenta como esta morre ao reportar centenas de achados na primeira execução, ou ao reportar progresso que ninguém fez. Seis coisas fazem frente:
As regras não disparam sem ambas as visões. Faça a varredura de um código-fonte sem contratos em lugar algum e todo endpoint tecnicamente se qualifica como uma shadow API não documentada. Esses achados não dizem nada além de que você não forneceu nenhuma documentação, então uma regra só é executada quando toda visão sobre a qual ela raciocina estava de fato na varredura. O relatório nomeia as regras que ficaram de fora.
Quase-acertos são reportados como dúvida, não como achados. "No código, não na documentação" é indistinguível de "em ambos, mas o alibi falhou em alinhá-los." Assim, um endpoint que cai em uma visão é verificado contra as outras em busca de um quase-acerto — mesmo caminho com um verbo diferente, ou a um segmento de distância onde um lado tem um parâmetro e o outro um literal. Achados que carregam um quase-acerto são rebaixados e sinalizados para revisão. Essa contagem fica ao lado dos totais, porque todo achado é tão confiável quanto menor ele for.