tl; dr:
Il n'est pas possible de faire une telle chose de manière vraiment sécurisée, mais cela peut être fait d'une manière "probablement assez bonne" pour être utilisable et acceptable .
Vos options sont essentiellement une forme de stockage crypté (avec le risque que les clés de cryptage soient volées, car elles doivent être présentes pour le décryptage), ou quelque chose impliquant du hachage, avec les problèmes bien connus du hachage mots de passe (un numéro de carte de crédit est fondamentalement un «mot de passe»).
Je mettrais en œuvre cela comme un système à deux niveaux où le premier niveau serait un simple CRC32 et le second serait plusieurs fois fonction de hachage sécurisée itérée. Oui, CRC32 n'est pas un hachage cryptographiquement sécurisé, mais cela n'a pas d'importance dans ce cas particulier, puisque le CRC n'est pas le maillon faible.
Si l'idée d'utiliser un non-cryptographiquement- L'algorithme sécurisé vous fait trop peur, vous pouvez toujours remplacer le CRC par un algorithme cryptographique secore et n'utiliser que par exemple les 32 bits les moins significatifs (ou 16, pour une plus grande marge) du hachage résultant.
La raison de cette approche est que la plage d'entrées possibles ne couvre que 39 bits environ [1] . Il est pratiquement impossible de hacher cet espace de clés de manière vraiment sécurisée tout en gardant le système opérationnel pour l'utilisation prévue.
Une attaque par force brute sur un espace de clés de 39 bits est non seulement théoriquement faisable, mais en fait assez trivial - à moins que chaque opération est extrêmement coûteuse.
La principale menace contre laquelle vous devez vous défendre est le vol de votre base de données, suivi de forcer brutalement vos hachages pour récupérer des numéros de carte valides. La prochaine meilleure chose qu'un attaquant pourrait faire serait d'interroger en ligne si un numéro inconnu qui hache de manière identique à un numéro soumis aléatoirement a déjà été utilisé, ou de demander si un numéro valide déjà connu a été utilisé (ni l'un ni l'autre n'est très utile, cependant!).
Les cartes de crédit sont généralement valables 5 ans, donc pour que le système soit sécurisé, il doit supporter au moins 5 ans de force brute. En d'autres termes, le travail effectué pour une seule vérification doit être si complexe sur le plan informatique qu'une machine de craquage multi-GPU dédiée ne peut pas effectuer plus de 2 ^ 39 / (5 * 365 * 86400) = 3486,5 vérifications par seconde.
Si l'on prend le chiffre bien connu de 348 milliards par seconde de 2012, la seule approche vraiment sécurisée devrait donc stocker la valeur d'avoir haché au moins 100 millions de fois. En tenant compte de la loi de Moore, ce serait 200 millions maintenant, et nous n'envisageons même pas la possibilité que quelqu'un possède 2 ou 3 de ces machines (ou peut-être 10).
Cependant, ceci encore ne prend pas en compte le fait que les banques sont par nature stupides et vont simplement incrémenter l'avant-dernier chiffre pour un nouveau numéro valide (et mettre à jour le chiffre de contrôle). Toutes mes cartes de crédit émises au cours des 20 dernières années ont eu le même numéro à l'exception de l'avant-dernier chiffre incrémenté de 0, 1, 2, 3, ...
Ce qui signifie que la planification sur 5 ans toujours ne suffit pas . Une personne connaissant un numéro de carte de crédit expiré peut dériver le numéro valide de la carte d'abonné. Il faut donc plutôt prévoir quelque chose comme 30 ans, pas 5 ans. Je vais laisser extrapoler la loi de Moore à 20-30 ans supplémentaires pour faire mes devoirs.
En conclusion, pour que le système soit vraiment, vraiment sécurisé , votre serveur devrait effectuer le l'équivalent d'un billion de hachages (ou plus) par vérification, ce qui à un taux de, disons 10 millions par seconde pour une implémentation CPU typique, prendrait plus d'une journée. En d'autres termes, le système est complètement inutilisable pour son objectif désigné .
Quelque chose de plusieurs ordres de grandeur plus rapide est nécessaire. La plupart des requêtes seront des requêtes négatives, et un hachage simple et rapide pourrait être utilisé pour éliminer 99,9% de tous les négatifs, si seulement cela ne rend pas la sécurité déjà faible encore plus faible. C'est là que CRC32 entre en jeu.
Si les CRC32 de deux numéros de carte de crédit ne correspondent pas , il est garanti que les numéros ne sont pas les mêmes. La plupart du temps, ce sera le cas, et vous pouvez immédiatement retourner "Non!". Vous pouvez sauter 99,9% du travail sans rien dévoiler.
Si les CRC correspondent , cela peut être un succès, mais il y a un risque de collision de hachage. Maintenant, le hachage cryptographique sécurisé (qui aurait au moins 160, mieux 256 bits) est calculé et comparé. La probabilité d'une collision est désormais négligeable. Si le hachage correspond, il est certain que le nombre correspond.
CRC32 contient 32 bits d'informations. Il est impossible de restaurer 39 bits d’information à partir de 32 bits, quelles que soient les ressources de calcul dont vous disposez. Par conséquent, le CRC est sûr à utiliser dans ce cas (ou du moins, il n'est pas moins sûr que toute autre chose).
Comme l'a souligné Ben Voigt, il est de bien sûr encore possible de deviner les informations qui ne peuvent pas être restaurées, et 7 bits à deviner ne sont pas terrible (concaténer la date d'expiration fera 15 bits). C'est vrai, mais vous ne pouvez pas faire grand-chose à ce sujet.
Qu'en est-il du CRC et de la sécurité de toute façon? Le CRC n'est pas sécurisé sur le plan cryptographique. Il est relativement facile de falsifier les bits pour obtenir la sortie souhaitée (pas de problème ici, ce serait avec les connexions), et la fonction peut être inversée de manière triviale (4 recherches de table, plus quelques décalages et xor) vers une entrée 32 bits, un problème un peu plus important. Heureusement, mais ce modèle de bits n'a pratiquement aucune valeur car ce n'est pas un nombre valide, ni un sous-ensemble d'un modèle de 39 bits qui pourrait être un nombre valide (autrement que par pure coïncidence).
Forcer brutalement l'espace de touches complet de 39 bits est plus simple que d'essayer de jouer des tours sur le CRC, car, malheureusement, c'est assez facile et rapide: une implémentation SSE4.2 utilise environ un demi-cycle par octet (donc, 2 cycles par hachage), ce qui signifie qu’un ordinateur de bureau pourrait faire l’espace de clés complet en une seconde ou deux (en supposant que les clés sont à comparer avec toutes les tailles en L1).
La recherche exhaustive révélerait tous les 39 bits modèles qui ont le même CRC, ce qui signifie qu'ils pourraient éventuellement être des numéros de carte de crédit, et en utilisant l'algorithme de Luhn, l'attaquant peut immédiatement rejeter 9 numéros sur 10 qui ne peuvent pas être valides. C'est mauvais, certes, mais c'est vraiment juste une conséquence de ne pas avoir trop de choix d'entrée et d'avoir un chiffre de contrôle implanté sur le dessus!
Pourtant, le CRC est en fait plus fort dans ce scénario plutôt qu'un algorithme cryptographiquement sécurisé: compte tenu de 2 à 3 milliards de cartes de crédit en circulation dans le monde, le risque de collision avec un hachage de 160 bits se situe entre 1 et 10 20 , et même pas pensez aux chances d'utiliser un hachage de 256 bits. Ce qui signifie que tout résultat lors de votre recherche exhaustive de l'espace de clés 39 bits vous donnera immédiatement le seul et unique numéro de carte valide garanti. Un hit sur le CRC32 ne vous donnera qu'un des nombreux numéros possibles.
Une chose que vous pourriez faire pour échanger un peu de vitesse contre la sécurité serait de jeter davantage d'informations sur le CRC, par exemple, vous pouvez simplement supprimer les 8 ou 16 bits les plus significatifs du CRC, ce qui les ajouterait aux bits qu'un attaquant devra deviner. Bien sûr, cela réduira quelque peu l'efficacité de la taille, mais pas trop drastiquement. Au lieu d'élaguer 99,99% du travail, vous pourriez finir par élaguer 99% ou 98%, ce qui est tout de même très bien.
Le deuxième niveau de vérification, comme indiqué ci-dessus, doit être un hachage cryptographiquement sécurisé qui exécute au moins un million d'itérations, un peu comme il est fait dans un schéma d'étirement de clé (en fait, il a besoin de beaucoup plus que cela , mais le système doit également rester pratiquement utilisable).
Le réalisateur doit ici échanger le risque contre l'utilisabilité, un serveur devrait au moins être capable de traiter quelques dizaines de requêtes par seconde. Les clients / commerçants ne consentiront pas si la recherche d'un numéro prend plusieurs minutes (ou plus), quelles que soient les implications de sécurité. Il n’est pas non plus pratique d’avoir plus ou moins un serveur dédié dédié par marchand.
Comme la correspondance n’est intéressante que sur une base par marchand, on peut utiliser une constante par marchand et stocker les numéros de carte de manière redondante avec un index sur l'identifiant du marchand, qui devrait être dans les pouvoirs de tout système de base de données raisonnable.
[1] Un numéro de carte de crédit comporte 16 chiffres de dont le dernier est une somme de contrôle dérivée des autres (algorithme de Luhn). Le deuxième mais le dernier chiffre est généralement (pas nécessairement, mais généralement) le numéro séquentiel de la carte, commençant à zéro pour la première carte du titulaire du compte, 1 pour le conjoint ou une carte de remplacement, 2 pour la carte suivante par la suite, et ainsi de suite. , les trois premiers chiffres encodent l'émetteur de la carte et la banque, et n'utilisent qu'environ la moitié du nombre possible de combinaisons à 3 chiffres.
Dans l'ensemble, cela nous laisse entre 12 et 13 chiffres décimaux complets d'entropie, ce qui se situe entre un peu plus de 36 bits et 39 bits.
Je recommanderais de concaténer la date d'expiration avec le nombre, car cela rendra cette situation un peu moins misérable. Mes cartes de crédit sont toujours valables 5 ans (je ne sais pas si c'est la règle universelle, mais je suppose que oui), donc l'ajout de la date d'expiration ajouterait 5 * 12 possibilités, ou 5,9 bits (celles-ci sont à peu près gratuites, puisque vous avez de toute façon besoin des données d'expiration dans une transaction!).