IDOR: quando autenticação existe mas autorização não
Trocar um número na URL não deveria abrir a porta do vizinho — mas é exatamente isso que IDOR permite.
IDOR (Insecure Direct Object Reference) é, na prática, o exemplo mais direto de um princípio que essa trilha já mencionou algumas vezes sem aprofundar: autenticação e autorização são perguntas diferentes. Um sistema pode acertar 100% na primeira (provar quem você é) e falhar completamente na segunda (decidir o que você pode acessar) — e é exatamente isso que IDOR explora.
O cenário: trocar um número na URL
Uma usuária, Ana, está logada e acessa o próprio pedido:
GET /pedidos/123 HTTP/1.1
Cookie: sessao=abc123 (sessão de Ana, autenticada normalmente)Nada impede Ana de simplesmente editar a URL na barra de endereço e pedir /pedidos/124 — um pedido de outra pessoa. Se o servidor responder com os dados normalmente, é porque ele checou só "existe uma sessão válida aqui?" e nunca chegou a perguntar "esse pedido específico pertence a quem está pedindo?".
class PedidosController < ApplicationController
before_action :authenticate_usuario! # só confirma QUEM está logado
def show
pedido = Pedido.find(params[:id]) # busca QUALQUER pedido pelo id, sem checar dono
render json: pedido
end
endauthenticate_usuario! cumpriu perfeitamente o papel dele — Ana está, de fato, autenticada. Pedido.find(params[:id]) é onde a falha mora: ele busca o registro pelo id recebido, sem nenhuma cláusula que restrinja isso ao usuário atual.
Autenticação vs. autorização, sem confundir de novo
Autenticação responde "quem é você?" — login, sessão, token, tudo que essa trilha cobriu até aqui. Autorização responde "o que você, especificamente, tem permissão de fazer ou ver?" — uma pergunta que precisa ser refeita a cada recurso acessado, não só uma vez no início da requisição. Um sistema pode ter uma autenticação impecável (hash de senha correto, JWT bem assinado, cookie com todos os atributos certos) e ainda assim estar cheio de IDOR, porque essas são camadas completamente independentes.
def show
pedido = Pedido.find(params[:id])
render json: pedido
end
# responde com QUALQUER pedido que exista, de qualquer usuáriodef show
pedido = current_usuario.pedidos.find(params[:id])
render json: pedido
end
# busca SÓ dentro da relação de pedidos do usuário atual —
# um id de outro usuário simplesmente não é encontrado (404)A correção nem precisa de uma biblioteca nova — trocar Pedido.find(...) por current_usuario.pedidos.find(...) já restringe a busca ao escopo certo desde a query. Se o id pedido não pertencer àquele usuário, o Active Record simplesmente não encontra nada e levanta RecordNotFound — que vira um 404, sem expor nem a existência do recurso de outra pessoa.
Por que id sequencial torna o ataque trivial de automatizar
Um detalhe que agrava (mas não causa) o problema: quando o identificador do recurso é um número sequencial (1, 2, 3...), um atacante nem precisa adivinhar nada — ele só varre a sequência inteira, /pedidos/1, /pedidos/2, /pedidos/3, e assim por diante, coletando cada resposta que não retornar erro. Trocar o id sequencial por um identificador não previsível (um UUID, por exemplo) dificulta essa varredura automatizada — mas é importante entender os limites disso: um UUID torna o ataque mais trabalhoso (o atacante precisaria descobrir ids válidos por outro meio, como um vazamento em outra tela), não impossível. A correção real continua sendo a checagem de autorização a cada acesso; um id difícil de adivinhar é só uma camada extra de dificuldade, não uma substituição pra ela.
/pedidos/124 → fácil de adivinhar varrendo sequência numérica
/pedidos/f3a9c1e8-... → difícil de adivinhar, mas AINDA precisa da checagem
de dono — um UUID vazado em outro lugar (um link
compartilhado, um log) continua funcionando sem elaExercício
Um endpoint PATCH /perfis/:id permite editar dados de perfil, e está implementado como Perfil.find(params[:id]).update(perfil_params), protegido só por authenticate_usuario!. Reescreva pra impedir que um usuário edite o perfil de outra pessoa, e explique por que isso ainda é considerado IDOR mesmo com autenticação funcionando perfeitamente.