MVC / REST doit-il renvoyer 403 ou 404 pour les ressources appartenant à d'autres utilisateurs?

33

Lorsque vous travaillez avec un site basé sur des ressources (telle qu'une application MVC ou un service REST), nous avons deux options principales lorsqu'un client essaie GETune ressource à laquelle il n'a pas accès:

  • 403 , qui dit que le client n'est pas autorisé ; ou
  • 404 , qui indique que la ressource n'existe pas (ou n'a pas pu être localisée).

La sagesse et la pratique communes semblent être de répondre par la vérité - c'est-à-dire un 403. Mais je me demande si c'est vraiment la bonne chose à faire.

Les systèmes de connexion sécurisés ne vous disent jamais la raison d'un échec de connexion. C'est-à-dire qu'en ce qui concerne le client, il n'y a pas de différence détectable entre un nom d'utilisateur inexistant et un mot de passe incorrect. Le but est de ne pas rendre les ID d’utilisateur - ou pire, les adresses électroniques - découvrables.

Du point de vue de la protection de la vie privée , il semble beaucoup plus sûr de retourner un 404. Je me souviens de l'incident dans lequel quelqu'un aurait découvert les gagnants d'une émission de téléréalité (Survivor, je pense) en regardant quelles ressources n'existaient pas sur le site. site vs qui ont fait. Je crains qu'un 403 puisse potentiellement donner des informations sensibles telles qu'un numéro de série ou un numéro de compte.

Existe-t-il des raisons impérieuses de ne pas renvoyer un 404? Une politique 404 pourrait-elle avoir des effets secondaires négatifs ailleurs? Si non, alors pourquoi la pratique n'est-elle pas plus courante?

Aaronaught
la source
1
Raison impérieuse de ne pas retourner 404: si le service est arrêté ou s'il y a un bogue / une erreur d'authentification, vous obtiendrez alors un 404, mais le client / utilisateur / testeur / développeur / personne de support essayant de diagnostiquer le problème peut ne pas avoir la moindre idée ce qui ne va pas du message d'erreur.
Steven Evers
@ Snorfus: C'est un bon point - je l'aurais mis dans une réponse. Bien que Josh ait déjà ajouté un bon contrepoint ...
Aaronaught
Un autre aspect à garder à l’esprit est le suivant: comment les 404 sont-elles traitées en aval? Existe-t-il un CDN ou une sorte de cache? Si vous souhaitez un jour pouvoir les mettre en cache, vous ne voudrez probablement pas que les 404 "utilisateurs ne disposent pas de l'autorisation" soient mis en cache.
pc1oad1etter

Réponses:

15

Il existe une idée fausse (et une utilisation abusive) générale associée à ceci 403 Forbidden: il n'est pas censé révéler quoi que ce soit à propos de ce que le serveur pense de la requête. Il est spécialement conçu pour dire,

Je comprends ce que vous demandez, mais je ne vais pas gérer la demande, peu importe ce que vous essayez. Alors arrête d'essayer.

Tout agent d'utilisateur ou client doit interpréter cela comme signifiant que la demande ne fonctionnera jamais et répondra de manière appropriée.

Cela a des implications pour les clients qui traitent les demandes pour le compte d'utilisateurs: si un utilisateur n'est pas connecté ou s'il utilise des types de caractères incorrects, le client qui gère la demande doit répondre: "Je suis désolé, mais je ne peux rien faire" après la première fois. il obtient le 403et cesse de traiter les demandes futures. Évidemment, si vous souhaitez qu'un utilisateur puisse toujours demander l'accès à ses informations personnelles après une défaillance, il s'agit d'un comportement hostile de l'utilisateur.

403est différent de 401 Authorization Requiredce qui indique que le serveur gérera la demande tant que vous transmettez les informations d'identification correctes. C'est généralement ce à quoi les gens pensent lorsqu'ils entendent 403.

Il est également en contraste avec 404 Page Not Foundqui, comme d' autres l' ont souligné, est conçu non seulement pour dire : « Je ne peux pas trouver cette page » , mais à suggérer au client que le serveur ne prétend pas que la réussite ou l' échec des demandes futures.

Avec 401et 404, le serveur ne dit rien au client ni à l'agent utilisateur quant à la marche à suivre: ils peuvent continuer à essayer dans l'espoir d'obtenir une réponse différente.

La 404manière appropriée de gérer une page que vous ne voulez pas montrer à tout le monde, mais que vous ne voulez pas révéler, est la raison pour laquelle vous ne la montrez pas dans certaines situations.

Bien entendu, cela suppose que le client à l'origine de la demande se soucie de la désinvolture des RFC. Un client assez malveillant ne se soucie pas du code d'état renvoyé, sauf de manière fortuite. On saura que c'est une page utilisateur masquée (ou une page potentiellement masquée) en la comparant à d'autres pages utilisateur connues.

C'est, disons votre gestionnaire est users/*. Si je sais users/foo, users/baret le users/baaztravail, le serveur renvoyant un 401, 403ou 404pour users/quuxne signifie pas que je ne vais pas essayer, surtout si j'ai des raisons de croire qu'il est un quuxutilisateur. Un exemple type de scénario est Facebook: mon profil est privé, mais mes commentaires sur les profils publics ne le sont pas. Un client malveillant sait que j'existe même si vous revenez 404sur ma page de profil.

Les codes d'état ne sont donc pas destinés aux cas d'utilisation malveillante, ils sont destinés aux clients qui respectent les règles. Et pour ces clients, une 401ou une 404demande est la plus appropriée.


la source
4
Bons points à propos de 401 contre 403. Je ne suis cependant pas d'accord avec la finalité de vos déclarations sur 404. Bien sûr, dans l'exemple de Facebook, vous savez déjà que cela quuxexiste. Mais il n'y aura pas toujours de preuves externes, en particulier sur des sites non sociaux où les données des clients sont vraiment privées . Un utilisateur fouineur ou hostile pourrait éventuellement être en mesure d' en déduire que vous mentez, mais pas nécessairement que les ressources que vous mentez au sujet . Je pense que le point essentiel ici est vraiment, ne vous souciez pas de 404 ressources, à moins qu’il n’y ait pas d’autres méthodes de découverte disponibles.
Aaronaught
@Aaronaught Le problème est que vous devez être vraiment, vraiment sûr que quelqu'un ne peut pas comprendre pourquoi le serveur est trompeur, ou qu'il n'existe aucune méthode de découverte contre laquelle vous n'avez pas enduré. Une personne assez intelligente le comprendra et à ce moment-là, le code de statut n'aura plus de sens.
1
Je ne comprends toujours pas comment une personne assez intelligente pourrait comprendre s'il n'y a pas de partage de données entre les profils d'utilisateurs. Je comprends que quelqu'un déterminé finira par se rendre compte "oh, un 404 signifie en réalité qu'il pourrait exister, mais je ne peux tout simplement pas y accéder" - mais en supposant que le serveur renvoie la même erreur pour des ressources qui n'existent pas réellement , comment faire la différence entre une ressource inexistante et une ressource privilégiée?
Aaronaught
@Aaronaught, la seule chose dont une personne aurait besoin de savoir, c'est que l'URL d'un profil devrait exister. Vous pouvez simplement utiliser des identifiants de profil et les incrémenter de manière pseudo (une personne ayant un identifiant de profil 3333 ne signifie pas qu'il existe une personne avec un identifiant de profil de 3332), mais une personne déterminée devrait pouvoir le prédire compte tenu de taille de l'échantillon d'identifiants valides. À défaut, et même avec un système complètement durci qui ne laisse aucune information sur la façon dont il génère les URL pour les pages de profil, il y a toujours de l'ingénierie sociale.
8

Selon RFC2616

10.4.4 403 interdit

Le serveur a compris la demande, mais refuse de l'exécuter. L'autorisation n'aidera pas et la demande NE DEVRAIT PAS être répétée. Si la méthode de demande n'était pas HEAD et que le serveur souhaite rendre publique la raison pour laquelle la demande n'a pas été remplie, il DEVRAIT décrire le motif du refus dans l'entité. Si le serveur ne souhaite pas mettre ces informations à la disposition du client, le code d'état 404 (non trouvé) peut être utilisé à la place.

Notez également que lors de l'accès à des ressources interdites, l' autorisation ne vous aidera pas .

Lie Ryan
la source
Je suis au courant de la RFC, bien qu'elle ressemble peu à la réalité. Presque aucun serveur explique toujours la raison d'un 403 au - delà de cette première phrase ( « Le serveur a compris la requête, mais refuse de le remplir. ») Et la plupart des cadres MVC ont même quelque chose de semblable à un HttpUnauthorizedResultqui sont destinés à être utilisés pour des ressources privilégiées . Je réalise aussi (évidemment) que 404 peut être utilisé à la place; ma question est de savoir si oui ou non il doit être utilisé, et ce qui doit être considéré lors de la prise de cette décision.
Aaronaught
@Aaronaught: la RFC ne vous permet pas seulement d'utiliser 404, elle recommande de lancer 404 lorsque vous ne souhaitez rien reconnaître.
Lie Ryan
3
C'est bien, mais quand dois-je ne rien reconnaître? Ou plutôt, quand devrais- je? C'est vraiment l'essence de la question.
Aaronaught
5

Devrais-tu? Oui .

Vous l'avez dit vous-même, trahissez le moins possible. Si j'attaquais un système et remarquais que le serveur répondait avec 403 codes, je me concentrerais sur ceux-ci au lieu de continuer. Mieux vaut une porte proclamer qu’elle n’existe pas que de la proclamer interdite.

L’inconvénient de l’utilisation des requêtes 404 est qu’à l’extérieur, il apparaîtra comme si la page n’existait pas, ce qui pourrait entraîner des conflits par rapport aux pages censées exister mais manquantes. Si vous n'êtes pas inquiet à propos des robots Web (les systèmes authentifiés doivent de toute façon être totalement refusés), vous devriez absolument y aller. Toutes les API que j'ai gérées traitent les accès non autorisés exactement de la même manière, tout comme StackOverflow . Vous ne pouvez pas voir cette page? Je vous assure qu'il ne exist, même si elle prétend ne pas.

Vous devez accepter des demandes lorsque la ressource est connue d'exister et l' accès est refusé. Un échec de la connexion ne devrait pas donner lieu à un message 404. Vous ne devez pas accuser réception des demandes lorsque l'existence de la ressource elle-même doit être protégée. L'accès au royaume existe dans le public, mais les groupes ou les rôles de sécurité qui le composent ne le sont pas.


Raison impérieuse de ne pas retourner 404: si le service est arrêté ou s'il y a un bogue / une erreur d'authentification, vous obtiendrez alors un 404, mais le client / utilisateur / testeur / développeur / personne de support essayant de diagnostiquer le problème peut ne pas avoir la moindre idée quel est le problème avec le message d'erreur

Les développeurs doivent avoir accès aux journaux, qui indiquent une tentative d'accès à une ressource protégée. Les clients / utilisateurs / testeurs généreront des commentaires qui finiront par toucher un développeur.

Sécurité par obscurité ... vraiment?

Ce n'est pas la sécurité par l'obscurité. Vous utilisez l'obscurité en plus des mesures de sécurité appropriées.

Les demandes valides obtenant un "404", par contre, ne font qu'ajouter de la complexité et de l'obscurité là où ce n'est pas nécessaire

Ce ne sont pas des demandes valides, ce sont des demandes non autorisées . Vous modifiez une petite partie (retournez 404 au lieu de 403) pour gagner un avantage substantiel sur tous les attaquants potentiels.

Josh K
la source
Sécurité par obscurité ... vraiment? Si quelqu'un essaie d'attiser vos services avec une intention malveillante, il sait déjà qu'il existe. Les demandes valides obtenant un "404", par contre, ne font qu'ajouter de la complexité et de l'obscurité là où ce n'est pas nécessaire.
Steven Evers
4
@ Snorfus: Il y a une distinction subtile à faire ici entre sécurité et confidentialité . La vie privée est, presque par définition, "par obscurité". Ceci est particulièrement important dans le contexte d'un système basé sur des ressources , car l'existence ou la non-existence d'une ressource est une information potentiellement importante. Il peut également y avoir des arguments de sécurité, bien que ceux-ci me préoccupent moins. Je voudrais vous en savoir plus sur cette complexité ajoutée; pouvez-vous entrer dans les détails au-delà de votre commentaire initial? (Peut-être une réponse plus complète? Avez-vous été mordu par 404? 40)?
Aaronaught
2
@ Snorfus: J'aimerais également ajouter, après coup, que la défense en profondeur n'est pas la même chose que la sécurité par l'obscurité . Ce dernier implique qu'il n'y a pas d' autre moyen de protection. Mais ajouter de l’obscurité à un système déjà sécurisé peut souvent être une bonne chose, à condition que cela ne pose pas de problème par la suite. Dans ce cas, il est évident que le système est déjà sécurisé, car les 404 sont émises par code d'autorisation.
Aaronaught
@Aaronaught: Je posterai une réponse plus détaillée, mais sur la question: si une ressource est privée, quel est le raisonnement qui sous-tend sa divulgation publique?
Steven Evers
@Snorfus: une ressource est privée d'un client - ou peut-être d'un groupe - et non du monde entier.
Aaronaught
0

Cela dépend vraiment des informations données par le code d'état 403. Si vous avez un noeud final d'API répondant GET /myresource/{id}avec un 404 lorsque la ressource n'existe pas, le code d'état renvoyé par le noeud final lorsque la ressource existe mais qu'il n'est pas autorisé à l'utilisateur actuel doit dépendre de la prévisibilité du idparamètre et du montant des informations qu'il contient par lui-même.

  • S'il ids'agit d'un champ privé tel qu'une adresse e-mail ou un numéro de compte bancaire, il devrait probablement toujours être caché derrière un 404. Dans le cas d'une adresse e-mail, cela pourrait empêcher les spammeurs de compiler une liste d'adresses e-mail valides enregistrées sur votre site Web.
  • S'il ids'agit d'un nom d'utilisateur public, ne vous inquiétez pas, il existe d'autres moyens pour accéder à ces informations (par exemple, il vous suffit de naviguer sur la page du forum de votre site Web).
  • Si idest un identifiant opaque mais prévisible (par exemple, un entier auto-incrémenté), vous ne donnez aucune information à l'attaquant qu'il ne pourrait pas obtenir par d'autres moyens. Donc, à mon avis, il est prudent de renvoyer un code d'état 403.
  • Si idest un identifiant opaque et imprévisible (comme un GUID aléatoire), la question est plus subtile. Personnellement, je pense qu’il n’ya aucun problème à renvoyer un code d’état 403. Ces informations ne peuvent être exploitées que si votre API utilise un autre point de terminaison défectueux, mais que le véritable défaut est votre autre point de terminaison.

Vous pouvez supposer qu'il vaut mieux prévenir que guérir dans tous les cas et cacher les informations quel que soit le contexte, mais vous ne pouvez pas vous fier à ce type de comportement pour fournir une forme de sécurité quelconque . D'autre part, il peut assurer la confidentialité (ou la confidentialité, comme d'autres l'ont dit).

Un mécanisme de sécurité ne devrait pas simplement être un ralentisseur pour l'attaquant, sinon il est tout simplement inutile. Dans ce cas, cela pourrait même vous empêcher d’utiliser correctement d’autres fonctionnalités (robots, Web Application Firewall recherchant des quantités anormales de 403 codes d’état pour bloquer les utilisateurs, etc.).

Maxime Rossini
la source