O MVC / REST deve retornar 403 ou 404 para recursos pertencentes a outros usuários?


33

Ao trabalhar com um site baseado em recursos (como um aplicativo MVC ou serviço REST), temos duas opções principais quando um cliente tenta GETum recurso ao qual não tem acesso:

  • 403 , que diz que o cliente não é autorizado ; ou
  • 404 , que diz que o recurso não existe (ou não pôde ser localizado).

O senso comum e a prática comum parecem ser responder com a verdade - isto é, um 403. Mas estou me perguntando se isso é realmente a coisa certa a se fazer.

Os sistemas de logon seguro nunca informam o motivo de uma falha no logon. Ou seja, no que diz respeito ao cliente, não há diferença detectável entre um nome de usuário inexistente e uma senha incorreta. O objetivo é não tornar identificações de usuário - ou, pior, endereços de email - detectáveis.

Do ponto de vista da privacidade , parece muito mais seguro retornar um 404. Lembro-me do incidente em que alguém supostamente descobriu os vencedores de um reality show (acho que o Survivor) observando quais recursos não existiam no site. site versus quais. Estou preocupado com o 403 potencialmente fornecer informações confidenciais como um número de série ou número de conta.

Existem razões convincentes para não retornar um 404? Uma política 404 poderia ter efeitos colaterais negativos em outro lugar? Caso contrário, por que a prática não é mais comum?


1
Razão convincente para não retornar 404: se o serviço estiver inoperante ou houver um erro / erro na autenticação, você receberá um 404, mas o cliente / usuário / testador / desenvolvedor / suporte que está tentando diagnosticar o problema pode não ter idéia o que há de errado na mensagem de erro.
Steven Evers

@ Snorfus: Esse é um bom argumento - eu colocaria em resposta. Embora Josh já tenha adicionado um bom contraponto ...
Aaronaught

Outro aspecto a ter em mente é o seguinte: como os 404s são tratados a jusante? Existe uma CDN ou algum tipo de cache? Se você quiser armazená-las em cache, provavelmente não deseja que seus 404s de "usuário não tenham permissão" sejam armazenados em cache.
pc1oad1etter

Respostas:


15

Existe um equívoco geral (e uso indevido) associado 403 Forbidden: ele não deve revelar nada sobre o que o servidor pensa sobre a solicitação. Foi projetado especificamente para dizer,

Eu recebo o que você está solicitando, mas não vou lidar com a solicitação, não importa o que você tente. Então pare de tentar.

Qualquer UA ou cliente deve interpretar isso para significar que a solicitação nunca funcionará e responder adequadamente.

Isso tem implicações para os clientes que manipulam solicitações em nome dos usuários: se um usuário não estiver logado ou digitar errado, o cliente que manipula a solicitação deverá responder: "Sinto muito, mas não posso fazer nada" depois da primeira vez. ele obtém 403oe deixa de manipular solicitações futuras. Obviamente, se você deseja que um usuário ainda possa solicitar acesso a suas informações pessoais após uma falha, esse é um comportamento hostil ao usuário.

403está em contraste com 401 Authorization Required, que não dar que o servidor irá processar o pedido, desde que você passar as credenciais corretas. Geralmente é isso que as pessoas pensam quando ouvem 403.

Também está em contraste com o 404 Page Not Foundque, como outros apontaram, foi projetado não apenas para dizer "Não consigo encontrar essa página", mas para sugerir ao cliente que o servidor não faz reivindicações de sucesso ou fracasso para solicitações futuras.

Com 401e 404, o servidor não diz nada ao cliente ou ao UA sobre como eles devem proceder: eles podem continuar tentando na esperança de obter uma resposta diferente.

Assim 404é a maneira apropriada de lidar com uma página que você não deseja mostrar a todos, mas não quer revelar nada sobre o motivo de não mostrá-la em determinadas situações.

Obviamente, isso pressupõe que o cliente que faz a solicitação se preocupe com a mesquinha mesquinha RFC. Um cliente mal-intencionado não se preocupa com o código de status retornado, exceto de maneira incidental. Alguém saberá que é uma página de usuário oculta (ou uma possível página de usuário oculta) comparando-a com outras páginas de usuário conhecidas.

Ou seja, digamos que seu manipulador seja users/*. Se eu sei users/foo, users/bare users/baaztrabalho, o servidor retornar um 401, 403ou 404por users/quuxnão significa que eu não vou experimentá-lo, especialmente se eu tenho razão para acreditar que não é um quuxusuário. Um cenário de exemplo padrão é o Facebook: meu perfil é privado, mas meus comentários em perfis públicos não. Um cliente mal-intencionado sabe que eu existo, mesmo que você retorne 404à minha página de perfil.

Portanto, os códigos de status não são para casos de uso mal-intencionados, são para os clientes que seguem as regras. E para esses clientes, uma 401ou uma 404solicitação é mais apropriada.


4
Bons pontos sobre 401 x 403. Não concordo com a finalização de suas declarações no 404. Claro, no exemplo do Facebook, você já sabe que quuxexiste. Mas nem sempre haverá evidências externas, especialmente em sites não sociais onde os dados do cliente são realmente privados . Um usuário intrometida ou hostil pode, eventualmente, ser capaz de deduzir que você está mentindo, mas não necessariamente que recursos você está deitado sobre . Eu acho que o ponto mais importante aqui é realmente, não se preocupe com os recursos 404, a menos que não haja outros métodos de descoberta disponíveis.
precisa saber é o seguinte

@Aaronaught O problema é que você precisa estar muito, muito certo de que alguém não pode descobrir do que o servidor está enganando, ou que não existe algum método de descoberta contra o qual você não tenha se esforçado. Uma pessoa bastante inteligente vai descobrir isso, e nesse ponto, o código de status é sem sentido.

1
Ainda não estou claro como uma pessoa suficientemente inteligente poderia descobrir se não há compartilhamento de dados entre perfis de usuário. Eu entendo que alguém determinado acabará percebendo "ah, um 404 realmente significa que ele pode existir, mas eu simplesmente não consigo acessá-lo" - mas assumindo que o servidor retorne o mesmo erro para recursos que realmente não existem, como seria sabe a diferença entre um recurso inexistente e um privilegiado?
Aaronaught

@Aaronaught, a única coisa que uma pessoa precisa saber é que o URL de um perfil deve existir. Você pode apenas usar IDs de perfil e incrementá-los de uma maneira pseudo (para que uma pessoa com um ID de perfil 3333 não signifique que há uma pessoa com um ID de perfil 3332), mas uma pessoa determinada deve ser capaz de prever isso, tamanho da amostra de IDs válidos. Caso contrário, e mesmo tendo um sistema completamente rígido que não vaza informações sobre como gera URLs para páginas de perfil, sempre há engenharia social.

8

De acordo com a RFC2616

10.4.4 403 Proibido

O servidor entendeu a solicitação, mas está se recusando a atendê-la. A autorização não ajudará e a solicitação NÃO DEVE ser repetida. Se o método de solicitação não foi HEAD e o servidor deseja tornar público o motivo pelo qual a solicitação não foi atendida, DEVE descrever o motivo da recusa na entidade. Se o servidor não desejar disponibilizar essas informações ao cliente, o código de status 404 (Não encontrado) poderá ser usado.

Observe também que, ao acessar recursos Proibidos, a autorização não ajuda .


Estou ciente da RFC, embora ela tenha pouca semelhança com a realidade. Quase nenhum servidor explica o motivo de um 403 além dessa primeira frase ("O servidor entendeu a solicitação, mas está se recusando a atendê-la.") E a maioria das estruturas MVC tem algo parecido com o HttpUnauthorizedResultque se destina a ser usado para recursos privilegiados . Também percebo (obviamente) que 404 pode ser usado; minha pergunta é se é ou não deve ser usado, eo que deve ser considerado quando tomar essa decisão.
Aaronaught

@Aaronaught: o RFC não permite apenas o uso do 404, ele recomenda que o 404 seja lançado quando você não quiser reconhecer nada.
Lie Ryan

3
Tudo bem, mas quando não devo reconhecer nada? Ou melhor, quando devo ? Essa é realmente a essência da questão.
Aaronaught

5

Você deveria? Sim .

Você mesmo disse, trair o mínimo possível. Se eu estivesse atacando um sistema e percebesse que o servidor respondeu com 403 códigos, eu me concentraria neles, em vez de seguir em frente. Melhor uma porta proclamar que ela não existe do que proclamar que está sendo barrada.

A desvantagem do uso de solicitações 404 é que, externamente, ela aparecerá como se a página não existisse, e isso poderia ter conflitos quando comparado às páginas que deveriam existir, mas que estão ausentes. Se você não está preocupado com os rastreadores da Web (os sistemas autenticados devem ser totalmente negados de qualquer maneira), você deve absolutamente fazê-lo. Toda API que manipule o acesso não autorizado exatamente da mesma maneira, assim como o StackOverflow . Não consegue ver essa página? Eu lhe asseguro que faz existir, mesmo que ele não afirma.

Você deve reconhecer pedidos quando o recurso é conhecido de existir e o acesso é negado. Um logon com falha não deve resultar em uma mensagem 404. Você não deve aceitar solicitações quando a existência do recurso em si deve ser protegida. O acesso à região existe em público, mas os grupos ou funções de segurança nela não são.


Razão convincente para não retornar 404: se o serviço estiver inoperante ou houver um erro / erro na autenticação, você receberá um 404, mas o cliente / usuário / testador / desenvolvedor / suporte que está tentando diagnosticar o problema pode não ter idéia o que há de errado na mensagem de erro

Os desenvolvedores devem ter acesso aos logs, o que indicará uma tentativa de acessar um recurso protegido. Clientes / Usuários / Testadores gerarão feedback que acabará atingindo um desenvolvedor.

Segurança pela obscuridade ... realmente?

Isso não é segurança pela obscuridade. Você está usando a obscuridade , além das medidas de segurança adequadas.

Pedidos válidos para obter um "404", por outro lado, estão apenas adicionando complexidade e obscuridade onde não é necessário

Eles não são solicitações válidas, são solicitações não autorizadas . Você está mudando uma pequena parte (retorne 404 em vez de 403) para obter uma vantagem substancial em qualquer possível atacante.


Segurança pela obscuridade ... realmente? Se alguém está tentando cutucar seu (s) serviço (s) com intenção maliciosa, ele já sabe que ele existe. Por outro lado, solicitações válidas para obter um "404" estão apenas adicionando complexidade e obscuridade onde não é necessário.
Steven Evers

4
@ Snorfus: Há uma distinção sutil a ser feita aqui entre segurança e privacidade . Privacidade é, quase por definição, "por obscuridade". Isso é especialmente importante no contexto de um sistema baseado em recursos , pois a existência ou não de um recurso é uma informação potencialmente importante. Pode haver argumentos de segurança também, embora eu esteja menos preocupado com eles. Eu gostaria de ouvir mais sobre essa complexidade adicional; você pode entrar em detalhes além do seu comentário inicial? (? Talvez em uma resposta mais abrangente Você foi mordido por 404'ed 403s?)
Aaronaught

2
@ Snorfus: Eu também gostaria de acrescentar, como uma reflexão tardia, que a defesa em profundidade não é a mesma coisa que segurança pela obscuridade . O último implica que não há outros meios de proteção. Mas adicionar obscuridade a um sistema já seguro geralmente pode ser uma coisa boa - desde que não cause outros problemas no caminho. Nesse caso, é certo que o sistema já está protegido, pois os 404s estão sendo emitidos pelo código de autorização.
Aaronaught

@Aaronaught: vou postar uma resposta mais aprofundada, mas sobre a questão: se um recurso é privado, qual é o motivo por trás da exposição pública?
Steven Evers

@ Snorfus: Um recurso é privado para um cliente - ou talvez para um grupo - e não para o mundo inteiro.
precisa saber é o seguinte

0

Realmente depende das informações fornecidas pelo código de status 403. Se você tiver um terminal da API respondendo GET /myresource/{id}com um 404 quando o recurso não existir, o código de status retornado pelo terminal quando o recurso existir, mas não estiver autorizado para o usuário atual, dependerá da previsibilidade do idparâmetro e da quantidade das informações que ele contém por si só.

  • Se idfor um campo particular como um endereço de email ou um número de conta bancária, provavelmente sempre deve estar oculto atrás de um 404. No caso de um endereço de email, isso pode impedir que os bots de spam compilem uma lista de endereços de email válidos registrados no seu site.
  • Se idfor um nome de usuário público, não se preocupe, existem outros meios para obter acesso a essas informações (por exemplo, apenas navegando na página do fórum do seu site).
  • Se idfor um identificador opaco, mas previsível (por exemplo, um número inteiro com incremento automático), você não fornece nenhuma informação ao invasor que ele não poderia obter por outros meios. Portanto, na minha opinião, é seguro retornar um código de status 403.
  • Se idé um identificador opaco e imprevisível (como um GUID aleatório), a questão é mais sutil. Pessoalmente, acho que não há problema em retornar um código de status 403. Essas informações só poderiam ser exploradas se houver outro ponto de extremidade defeituoso na sua API usando esse ID, mas a falha real É o seu outro ponto de extremidade.

Você pode supor que é melhor prevenir do que remediar em qualquer caso e ocultar as informações em qualquer contexto, mas na verdade não pode confiar nesse tipo de comportamento para fornecer qualquer forma de segurança . Por outro lado, pode fornecer confidencialidade (ou privacidade, como outros já disseram).

Um mecanismo de segurança não deve ser apenas uma lombada para o invasor, caso contrário, é simplesmente inútil. Nesse caso, pode até impedir que você use outros recursos corretamente (rastreadores, firewall de aplicativos da Web procurando quantidades anormais de códigos de status 403 para bloquear usuários ...).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.