Pourquoi ne pas exposer une clé primaire

53

Au cours de ma formation, on m'a dit qu'il est impensable d'exposer les clés primaires réelles (non seulement les clés de base de données, mais tous les accesseurs principaux) à l'utilisateur.

J'ai toujours pensé que c'était un problème de sécurité (car un attaquant pourrait essayer de lire des choses qui ne sont pas les leurs).

Maintenant, je dois vérifier si l'utilisateur est autorisé à accéder de toute façon, y a-t-il une raison différente derrière cela?

De plus, comme mes utilisateurs doivent accéder aux données de toute façon, il me faudra une clé publique pour le monde extérieur quelque part entre les deux. Maintenant, cette clé publique a les mêmes problèmes que la clé primaire, n'est-ce pas?


Il y a eu la demande d'un exemple sur pourquoi faire cela de toute façon, alors en voici un. Gardez à l'esprit que la question concerne le principe lui-même et pas seulement s'il s'applique dans cet exemple. Les réponses à d'autres situations sont explicitement les bienvenues.

Application (Web, mobile) qui gère l’activité, a plusieurs interfaces utilisateur et au moins une API automatisée pour la communication intersystème (par exemple, le service de la comptabilité veut savoir combien facturer le client en fonction de ce qui a été fait). L'application ayant plusieurs clients, la séparation de leurs données (logiquement, les données sont stockées dans le même DB) est un élément essentiel du système. Chaque demande sera vérifiée pour la validité, peu importe quoi.

L'activité est très fine, de sorte qu'elle se trouve dans un objet conteneur, appelons-la "tâche".

Trois cas d'utilisation:

  1. L'utilisateur A veut envoyer l'utilisateur B à une tâche de sorte qu'il lui envoie un lien (HTTP) pour y effectuer une activité.
  2. L'utilisateur B doit sortir du bâtiment pour qu'il ouvre la tâche sur son appareil mobile.
  3. La comptabilité veut facturer la tâche au client, mais utilise un système comptable tiers qui charge automatiquement la tâche / activité à l'aide d'un code faisant référence à l'API REST de l'application.

Chaque cas d'utilisation nécessite (ou devient plus facile si) l'agent d'avoir un identificateur adressable pour la tâche et l'activité.

Angelo Fuchs
la source
3
liées: Une clé de substitution devrait-elle être exposée à un utilisateur? "Vous devez être prêt pour tout identifiant exposé aux utilisateurs / clients devant être modifié, et modifier l'identité d'une ligne dans une base de données et propager ce changement sur toutes les clés étrangères, c'est simplement demander de casser des données ..."
moucher
@gnat a ON UPDATE CASCADEété conçu pour cela (spécifique à mysql?), bien que si le problème est lié à la sécurité, la vérification de l'accès doit être effectuée sur le serveur principal et ne doit en aucun cas faire confiance à l'utilisateur
Izkata
2
@ Izkata Oui, sauf lorsque vous les référencez dans un magasin de données différent (ID utilisateur dans LDAP, à titre d'exemple simple), ou que vous devez récupérer des données à partir d'une sauvegarde. moucheron a un bon point là.
Angelo Fuchs
Pouvez-vous expliquer ce que vous voulez dire par "exposer"? Un exemple concret pourrait aider. :-)
CodeCaster
"exposer" signifie le montrer à l'utilisateur. (Par utilisateur, je veux dire principalement un humain, mais la question semble valable pour les machines aussi)
Angelo Fuchs

Réponses:

38

De plus, comme mes utilisateurs doivent accéder aux données de toute façon, il me faudra une clé publique pour le monde extérieur quelque part entre les deux.

Exactement. Prenez le HTTP sans état, qui autrement ne saurait pas quelle ressource il devrait demander: il expose l'ID de votre question 218306dans l'URL. Peut-être vous demandez-vous si un identifiant exposé est prévisible ?

Les seuls endroits où j'ai entendu une réponse négative à cette question sont les suivants: "Mais ils peuvent modifier l'ID dans l'URL!" . Ils ont donc utilisé des GUID au lieu d'implémenter les autorisations appropriées.

Je peux imaginer une situation dans laquelle vous ne voulez pas que vos identifiants soient prévisibles: la récolte de ressources. Si vous avez un site qui accueille publiquement certaines ressources d' autres peuvent être intéressantes, et vous les accueillir comme /images/n.jpgou /videos/n.mp4nest juste un nombre incrémenter, tous ceux qui cherchent à le trafic vers et depuis votre site Web peuvent récolter toutes vos ressources.

Donc, pour répondre directement à votre question: non, il n’est pas mauvais d’exposer directement les identifiants qui n’ont de sens que pour votre programme, il est même généralement nécessaire que votre programme fonctionne avec succès.

CodeCaster
la source
2
Les URL impossibles à deviner (contenant par exemple un jeton 128 bits cryptographiquement aléatoire) constituent une forme d'autorisation appropriée.
CodesInChaos
Propre comme extrêmement sensible à rejouer les attaques? C'est bien pour une utilisation ponctuelle comme une URL de réinitialisation de mot de passe, mais moins pour identifier une ressource statique, car une fois le jeton ouvert, tout le monde peut l'utiliser, sans que vous puissiez le modifier sans rompre toute référence légitime à il.
CodeCaster
hm? De toute évidence, cela nécessite SSL, mais c'est le cas, peu importe la méthode utilisée pour l'authentification et l'autorisation. Sur SSL, un attaquant ne peut pas apprendre le jeton (tout comme il ne peut pas apprendre les cookies) et empêche également les attaques par rejeu. Le principal inconvénient de cette approche est que vous ne pouvez pas révoquer l'accès pour des utilisateurs individuels. Je préfère donc l'utiliser uniquement pour des ressources immuables. Révoquer l'accès à des ressources immuables n'a pas de sens puisqu'un attaquant pourrait simplement stocker une copie locale.
CodesInChaos
2
Il semble que je sois incapable d'exprimer ce que je veux dire, je suis désolé. Je veux dire que l'utilisation d'un jeton aléatoire pour une ressource statique, par opposition à un identifiant incrémentiel, convient, si vous voulez que la ressource soit accessible au public mais ne peut pas être devinée. Pour toute autre utilisation, je préférerais une utilisation ponctuelle, en raison de la révocation.
CodeCaster
1
Aucun, mon point exactement. Pouvez-vous peut-être préciser ce que vous voulez dire par "exposer"?
CodeCaster
29

Vous ne devez pas l'exposer, car les personnes qui l'aperçoivent commenceront à l'utiliser comme «numéro de compte», ce qui n'est PAS. Par exemple, je connais mon numéro de compte pour mon compte bancaire. Je l'ai mémorisé, je l'utilise au téléphone avec le service clientèle, je l'utilise pour remplir des formulaires permettant à d'autres banques d'effectuer des virements, des documents légaux, mon service de paiement automatique, etc. Je ne veux pas ça change. La clé primaire (pour mon compte) en revanche, je ne sais pas ou ne vois jamais.
Le système qui le stocke change, au fil des années, d’un système à l’autre, lors de fusions bancaires, de mises à niveau et de remplacements de systèmes, etc., etc.
Les clés principales peuvent être modifiées au cours de certaines de ces transformations. par tout utilisateur régulier qui '
Les clés sans signification commerciale sont souvent appelées clés de substitution et sont souvent (mais pas toujours) utilisées comme clés primaires.

En fait, cela se produit même en interne lorsque des personnes ont construit des interfaces et des programmes qui utilisent mal et exposent les clés primaires et les intègrent à de tels systèmes au lieu de ne faire qu'une chose: identifier de manière unique un enregistrement de base de données en interne. J'ai en fait appris ce qui précède au cours d'une période de six ans au service d'un système d'entrepôt de données dans un hôpital.

Michael Durrant
la source
4
+1 mais ce que vous décrivez ici est en réalité une clé de substitution . Toutes les tables ne disposent pas d'une clé de substitution et même si c'est le cas, la clé de substitution n'est peut-être pas la clé "primaire".
Nvogel
2
+1 Je pensais que le numéro de compte serait la clé de substitution mais je l'ai lu et vous êtes 100% correct :)
Michael Durrant
2
+1 l'exposer aux utilisateurs ajoute des exigences implicites (par exemple, rester statique)
Matt
1
Très bonne réponse. En termes clairs, les clés de substitution sont utiles car personne ne s'en soucie et personne ne se soucie donc de les modifier ou de ne pas les changer. Si vous les exposez, les gens vont commencer à s'intéresser à eux.
JimmyJames
tl; dr: parce que l'avenir. Si un élément externe s'appuie sur une clé, les choses se compliquent si la mise en œuvre change plus tard. alors gardez-les plus ou moins cachés pour faciliter les choses.
Adam Tolley
27

Parce que les clés primaires sont un détail d'implémentation.

Si vous migrez des bases de données, vos clés primaires peuvent changer en raison de l'ordre d'insertion, de la suppression d'anciens enregistrements, etc. pour différentes raisons. Si vous migrez des plates-formes de base de données , il est possible que vous n'ayez plus de clé primaire réelle. Exposer la PC au-dessus de la couche d'accès aux données est une abstraction qui fuit, avec tous les problèmes de couplage que cela implique.

Telastyn
la source
3
Comment une couche d'application va-t-elle identifier de manière unique une ressource à partir de laquelle elle souhaite extraire ou mettre à jour la couche de données sans clé primaire?
CodeCaster
2
@CodeCaster - soit par un ensemble de données indexé unique, soit par une clé primaire non publique qui est renvoyée avec l'objet fourni par la couche d'accès aux données.
Telastyn
1
@CodeCaster - Il existe de nombreuses façons de créer un jeton qui permet au rappel de spécifier quelle opération est effectuée, et toutes ne font pas que simplement passer la clé primaire de part en part.
Telastyn
2
Mais pour cela, la couche de données doit savoir à quel jeton appartient (ou se traduit) à quelle PK. Pour moi, cela ressemble à une couche supplémentaire de complexité inutile, simplement dans le but de cacher la PK. A quoi sert-il, mis à part satisfaire l'architecte? Je suis d'accord avec ce que vous dites, je ne trouve tout simplement pas cela applicable dans une utilisation réelle et apprécierais un exemple réel.
CodeCaster
1
@CodeCaster - Non, le niveau intermédiaire fait son travail et résume le fait qu'il existe un accès aux données à partir de l'interface utilisateur. Il y a beaucoup de mauvais architectes dans le monde, mais bon nombre des meilleures pratiques en matière de conception de programme existent pour une raison. Certaines applications peuvent prendre le risque de cette abstraction qui fuit et d'autres non.
Telastyn
10

Ceci est une réponse combinée des autres (alias. Ce que j'ai appris). Si vous avez le goût de voter pour celui-ci, vous devriez au moins encourager l'un des autres ainsi que le travail effectué. Si vous êtes plus intéressé, lisez plutôt les autres réponses.

Vous ne devez pas exposer la clé primaire de la base de données mais utiliser une clé de substitution.

  1. Si vous voulez que vos utilisateurs soient capables de se souvenir (au moins un peu) ou de reconnaître l'identifiant d'une entrée. ( Réponse de Graystone28s )
  2. Si vous souhaitez planifier à l'avance et considérez que vous pouvez modifier les systèmes (de base de données ou autre) susceptibles de modifier votre PK. ( Réponse Telastyns )
  3. Si vous voulez vous assurer que vos utilisateurs disposent d’un moyen cohérent d’accéder aux données qui ne changeront pas, même si votre société change de propriétaire et que les données sont complètement migrées vers un système différent. ( Réponse de Michael Durrants )
  4. Si votre PC est prévisible (comme une séquence), votre système peut subir des problèmes de collecte des ressources. ( Réponse de CodeCasters ) Ceci ne s'applique que si votre système contient des informations qui valent la peine d'être recueillies et qui sont accessibles à quiconque ou au moins à une personne ayant un intérêt à l'exploitation.

Remarque: votre clé créée doit être (un peu) compréhensible pour l'homme ( réponse de Sqlvogels ).

Si votre système n'a pas besoin de 1. à 4., il n'y a aucune raison de ne pas utiliser les bases de données PK comme identifiant public (plusieurs réponses). De plus, la sécurité n’est pas un problème ici (plusieurs réponses).

Angelo Fuchs
la source
8

Une des raisons pour lesquelles j'ai trouvé, c'est que, dans le temps qui passe, j'ai vu des utilisateurs finaux demander à leur identifiant de signifier quelque chose (comme avoir un préfixe ou un indicateur de l'année où il a été créé). Changer une PK est difficile, mais une mère porteuse est beaucoup plus facile.

Votre clé principale sera probablement un élément sur lequel vous souhaitez que votre base de données indexe pour des raisons de performances, et vous pourrez éventuellement, pour des raisons techniques, la modifier, par exemple d'un nombre à un guide ... vous ne savez pas pour quelles raisons les nouvelles technologies ou les nouvelles connaissances pourrait vous guider vers le bas. Votre pk est votre élément technique de données, la clé publique est destinée à la consommation des utilisateurs finaux.

Wayne M
la source
7
La question est: "Est-il mauvais d'exposer les clés primaires?" . Votre réponse: "Les utilisateurs voudront peut-être avoir leurs propres identifiants" . Je ne comprends pas la relation. J'expose InvoiceNumber, ce qui a un sens pour le client et est modifiable par le client, mais j'expose également InvoiceID, que mon code utilise pour identifier de manière unique la facture. Vous n'avez pas à (et plus souvent ne le souhaitez pas) laisser la clé utilisateur être la clé de stockage. Cette question concerne ce dernier.
CodeCaster
Je pense que c’est un bon exemple, car si vous passez à la version multi-locataires de votre APP, vous pouvez conserver la même syntaxe et avoir plusieurs factures du même InvoiceNumber(pour des locataires différents), mais avoir des clés primaires différentes - un point (type de connexion). ) mentionné dans la réponse également.
Recluze
1
@ CodeCaster cette question est en fait sur "pourquoi ne voulez-vous pas qu'ils soient les mêmes"?
Angelo Fuchs
Dans ce cas, voir la réponse de Telastyns .
CodeCaster
2

Pour la plupart des applications, il est essentiel que vous exposiez les clés aux utilisateurs. Pour utiliser efficacement un système d’information, les utilisateurs de ce système ont normalement besoin d’un moyen d’identifier les informations qu’il contient et de les lier à quelque chose du monde qui se trouve en dehors de la base de données. En termes de bases de données relationnelles, ces identificateurs sont des clés.

Un modèle de conception bien utilisé consiste à créer une clé supplémentaire, purement "technique" pour les tables de base de données en tant que moyen d'abstraction. Par exemple, fournir une clé stable (relativement invariable) lorsque certaines clés alternatives sont susceptibles de changer. De telles clés techniques ne sont généralement pas exposées aux utilisateurs finaux, car cela sape l'abstraction voulue par rapport aux exigences de l'utilisateur. Cela n'a rien à voir avec la sécurité.

Le problème / malentendu implicite dans votre question est dû à une utilisation inappropriée du terme primaire clé. Une clé primaire n'est que l'une des clés "candidates" (plusieurs identifiants possibles dans une table de base de données). La clé primaire ne nécessite pas nécessairement de propriété fondamentalement différente de toute autre clé. Les assertions et les principes de conception qui s'appliquent spécifiquement aux clés primaires et non à d'autres clés sont toujours suspects et souvent erronés.

Étant donné que vous devez généralement exposer une clé à votre utilisateur, quelle doit être cette clé? Essayez de rendre vos clés familières, simples et stables. La familiarité et la simplicité rendent les clés faciles à lire et à mémoriser et aideront à éviter les erreurs de saisie de données. La stabilité signifie que les changements clés sont peu fréquents, ce qui permet également d'éviter toute possibilité d'erreur d'identification.

nvogel
la source
1
ça dépend ... de quoi? Je veux savoir quelles sont les raisons derrière ce concept générique pour savoir quand et quand l’appliquer.
Angelo Fuchs
1
Bonjour client, donnez-moi votre identifiant afin que je puisse vous aider. Bien sûr, son gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456. Hmm, qu'en est-il de votre social? ... identité de substitution
Michael Durrant
@Michael, réponse mise à jour. Est-ce une clé familière, simple et stable?
Nvogel
1

Ceci est tiré d'un commentaire sur la réponse de Greystone28 par CodeCaster. C'est un exemple de ce que vous dites:

J'expose InvoiceNumber, qui a une signification pour le client et est modifiable par celui-ci, mais j'expose également InvoiceID, que mon code utilise pour identifier de manière unique la facture. Vous n'avez pas à (et plus souvent ne le souhaitez pas) laisser la clé utilisateur être la clé de stockage. Cette question concerne ce dernier.

Quel est le but de l'affichage de InvoiceID dans votre application?

En exposant, je suppose que vous voulez dire que l'utilisateur peut le voir. Exposez-le uniquement si l'utilisateur en a besoin pour utiliser votre application. Il pourrait être utilisé par le support technique ou par des tâches administratives. J'ai travaillé avec quelques applications qui font cela. Cela facilite la tâche lorsque je connais le document en question.

JeffO
la source
Les factures ont des identifiants naturels (numéros) mais uniquement pour ceux que vous écrivez. Qu'en est-il de ceux que vous obtenez? Ils ont des numéros de facture, mais ils se chevauchent (parce que deux entreprises utilisent le même et que toutes les deux vous envoient une facture). Dans cette situation, votre InvoiceID est unique, le numéro n'est pas et ce qui le rend unique serait le nom d'utilisateur, qui n'est pas un bon identifiant pour les données (trop long, changements trop souvent, peut contenir des caractères obscurs ...)
Angelo Fuchs
@AngeloNeuschitzer - Si l'utilisateur peut identifier une facture de manière unique par son nom et son numéro de client, l'utilisateur n'a pas besoin du PK InvoiceID, mais la base de données et le code sous-jacent peuvent l'utiliser. Ce sont des fonctions mutuellement exclusives.
JeffO
Voir les cas 1 à 3 de mon exemple. Dans aucun de ces cas, le nom du client est un moyen utile de traiter cet objet pour l'utilisateur (que ce soit un humain ou une machine). InvoiceID PK est.
Angelo Fuchs
1

Il est tout à fait normal que les entités possèdent un identifiant unique qui est exposé au monde extérieur. Pour certains objets, il peut être possible de trouver un identifiant qui a réellement une signification (par exemple, le numéro de facture), mais pour d'autres, un tel identifiant n'existe pas et doit donc être généré.

Dans un souci de cohérence et de lisibilité, il est recommandé à toutes les entités d'un système d'utiliser exactement le même type et le même nom pour leur identifiant. Normalement, cet identifiant serait exposé ( <type> getId()) dans une classe de base abstraite.

Pour la même raison, chaque service dans le système (par exemple, le service de facturation) doit fournir des méthodes identiques pour accéder aux entités par leur identifiant. Normalement, cette méthode ( findById(<type> id)) serait héritée d'une interface de service générique ou d'une classe de base.

Cet identifiant ne doit pas nécessairement être la clé primaire de l'entité, mais il peut en être une. La seule chose à garantir est que la stratégie de génération de clés génère des identifiants raisonnablement uniques (pas nécessairement universellement uniques mais au moins dans le système).

Si le système est migré par la suite (gros si mon expérience le permet) vers une autre base de données, utiliser une stratégie différente (non basée sur des clés primaires) pour la création des identificateurs ne pose pas de problème, à condition que la stratégie soit compatible avec celle d'origine.

Muton
la source
Pouvez-vous expliquer ce qui dans votre réponse n'a pas été répondu aux autres?
Angelo Fuchs
2
Dans ma réponse, je suis en désaccord au moins avec les points 2. et 3. de votre résumé. Je ne pense pas que ce soient des raisons valables de ne pas utiliser les PK comme identificateurs d'objet.
Muton
0

La clé primaire existe, tout comme un descripteur du tuple (enregistrement, ligne) auquel vous essayez d'accéder en tant que développeur. Il est également utilisé dans l'intégrité référentielle (contraintes de clé étrangère) et peut-être aussi avoir un ou plusieurs cas d'utilisation.

Essentiellement, il n’ya rien de mal à l’exposer aux utilisateurs, voire aux pirates. Parce que je ne connais pas d'attaque utilisant une clé primaire par exemple.

Mais en matière de sécurité, nous avons de nombreux principes (que nous acceptons et n’approuvons pas) et nous devons les respecter:

  1. Le principe du privilège du bail
  2. La sécurité à travers l'obscurité

Et quelques autres principes. Ce qu'ils disent essentiellement est que:

Si vous n'avez pas besoin d'exposer vos données, pourquoi le voudriez-vous?

Saeed Neamati
la source
La partie poignée est où je suis d'accord. La sécurité n'est pas. Cela peut être important pour la sécurité, mais le fait d’avoir une clé interne indépendante qui n’est pas visible par l’utilisateur n’est généralement pas une question de sécurité. J'appellerais cela un bel effet secondaire.
JensG
Pourquoi voudriez-vous: voir l'exemple que j'ai ajouté à la question.
Angelo Fuchs