Uma fatura é devolvida a outra conta.
Um exemplo fictício de como um achado é documentado, da evidência ao reteste. Domínios, contas e dados são inventados.
Escopo
No escopo: app.example.com e api.example.com/v1, testados com duas contas de teste autorizadas. Excluído por acordo: páginas de pagamento de terceiros. A autenticação foi confirmada no escopo, e este teste externo não precisou de código-fonte.
Contas de teste
session=test-account-a
Dona da fatura demo-01
session=test-account-b
Dona da fatura demo-02
Requisição e resposta
Autenticados como a conta de teste A, pedimos uma fatura que pertence à conta de teste B.
GET /api/invoices/demo-02 HTTP/1.1 Host: api.example.com Cookie: session=test-account-a
{ "invoice": "demo-02",
"owner": "test account B"}A API devolveu a fatura da conta B para a conta A. Um pesquisador reproduziu o resultado antes de reportá-lo.
Passos para reproduzir
- Entre em app.example.com como a conta de teste A.
- Envie GET /api/invoices/demo-02 com a sessão da conta A.
- Observe uma resposta 200 com a fatura da conta B.
- Repita como a conta B para confirmar que demo-02 pertence a B.
Contexto de código Escopo proposto do Defense
Caminho: aplicação web, depois o serviço de cobrança, depois a consulta da fatura. O handler carrega uma fatura pelo id e a devolve sem conferir o dono.
export async function getInvoice(req, res) {
const invoice = await invoices.find(req.params.id)
return res.json(invoice) // owner not compared}Caminho sugerido: compare o dono da fatura com a conta autenticada antes de devolvê-la.
Revisão dos desenvolvedores
Os seus desenvolvedores revisam a orientação e decidem a mudança. Uma versão possível:
const invoice = await invoices.find(req.params.id) + if (!invoice || invoice.accountId !== req.session.accountId) {+ return res.status(403).end()+ } return res.json(invoice)
Expectativa do reteste
Depois da correção do seu time, repetimos a mesma requisição autorizada dentro do escopo.
As faturas da própria conta A ainda devem retornar 200.403