Maison  >  Article  >  interface Web  >  Pourquoi utilisons-nous les bibliothèques OTP alors que nous pouvons simplement faire Math.random()

Pourquoi utilisons-nous les bibliothèques OTP alors que nous pouvons simplement faire Math.random()

王林
王林original
2024-08-17 20:30:32384parcourir

Why do we use OTP libraries when we can just do Math.random()

Les mots de passe à usage unique (OTP) sont largement utilisés à des fins d'authentification et de vérification dans diverses applications et services. Un serveur les génère généralement et les envoie à l'utilisateur par SMS, e-mail ou autres canaux. L'utilisateur saisit ensuite l'OTP pour confirmer son identité ou effectuer une action.

J'ai eu une tâche dans laquelle nous devions implémenter la vérification basée sur OTP dans Node JS. Avant d'intégrer quelque chose comme ça, je suis sûr que la plupart d'entre nous, développeurs/ingénieurs, recherchons sur Internet les meilleures pratiques, les didacticiels, les tendances techniques récentes et les problèmes auxquels d'autres systèmes logiciels majeurs sont confrontés lors de leur implémentation. Alors je l'ai fait, et ce qui a le plus attiré mon attention, ce sont des bibliothèques comme otp-lib et otp-generator, dont la seule fonction était de générer un OTP. Le reste des tâches, comme l'envoi par SMS ou par e-mail, doit encore être effectué par d'autres moyens. La première question qui nous vient à l'esprit après avoir su que de telles bibliothèques existent est pourquoi nous devons faire autant d'efforts pour utiliser une bibliothèque pour générer des OTP alors que tout ce que nous avons à faire est d'écrire une seule ligne :

const otp = Math.ceil(Math.random() * 10000)

Dans cet article de blog, j'expliquerai ce que j'ai appris lors de notre petite recherche sur les générateurs OTP, pourquoi utiliser Math.random() pour générer des OTP est une mauvaise idée, quelles sont les autres façons de générer un OTP et pourquoi une bibliothèque devrait être utilisé pour une telle tâche ?

Types de nombres aléatoires

Il existe principalement deux types de nombres aléatoires :

  • Nombres pseudo-aléatoires (PRN)
  • Nombres aléatoires cryptographiques (CRN).

Nombres pseudo-aléatoires

Les nombres pseudo-aléatoires sont générés par un algorithme qui prend une valeur initiale, appelée graine, et produit une séquence de nombres qui semblent aléatoires. Cependant, l’algorithme est déterministe, ce qui signifie que si vous connaissez la graine et l’algorithme, vous pouvez prédire le prochain numéro de la séquence. Math.random() de Javascript et random.randInt() de Python sont un exemple de générateur de nombres pseudo-aléatoires.

Nombres aléatoires cryptographiques

Les nombres aléatoires cryptographiques sont générés par un processus imprévisible et ne peuvent être reproduits ou devinés. Ils sont généralement basés sur un phénomène physique, tel que le bruit atmosphérique, le bruit thermique ou les effets quantiques.

Comment fonctionne Math.random() ?

Différents moteurs Javascript se comportent un peu différemment lors de la génération d'un nombre aléatoire, mais tout se résume essentiellement à un seul algorithme XorShift128+.

XorShift est un algorithme déterministe, qui utilise l'addition comme solution de transformation non linéaire plus rapide. Comparé à ses pairs, qui utilisent la multiplication, cet algorithme est plus rapide. Il a également moins de chances d'échec que Mersenne Twister (utilisé par le module aléatoire de Python)

L'algorithme prend en compte deux variables d'état, leur applique un XOR et un décalage, et renvoie la somme des variables d'état mises à jour qui est un nombre entier. Les états sont généralement générés à l'aide de l'horloge système car c'est une bonne source pour un numéro unique.

Une implémentation de XOR shift plus en javascript ressemble à ceci :

let state0 = 1;
let state1 = 2;
function xorShiftPlus() {
    let s1 = state0; 
    let s0 = state1; 
    state0 = s0;  
    s1 ^= s1 << 23;
    s1 ^= s1 >> 17;
    s1 ^= s0;
    s1 ^= s0 >> 26;
    state1 = s1;
    return state0 + state1;
}

L'entier renvoyé est converti en double à l'aide de l'opération OU avec une constante. Vous pouvez trouver l'implémentation détaillée sur le code source de Chrome.

Comment prédire un nombre aléatoire généré par Math.random()

Prédire le résultat de Math.random() est difficile, mais ce n'est pas complètement impossible. Connaissant l'algorithme, vous pouvez facilement régénérer les mêmes nombres aléatoires si vous connaissez les valeurs de state0 et state1.

Ingénierie inverse XorShift128+ À l'aide d'un prouveur de théorème Z3, vous pouvez trouver la valeur de state0 et state1 en fournissant 3 nombres aléatoires consécutifs générés par un serveur.

L'implémentation du solveur Z3 peut être trouvée ici.

Maintenant, la question se pose de savoir comment obtenir ces 3 nombres aléatoires à partir d'un serveur. C'est la partie la plus difficile, et peut être obtenue dans certains des cas suivants :

  1. If an API returns a randomly generated number in its response or headers, it can easily be obtained by sending requests at set intervals.
  2. API documentation like OpenAPI/Swagger in modern applications is generated on the server. Sometimes their responses can contain an example value that uses a random number.
  3. With frameworks like NextJS that use server-side rendering while also being capable of handling backend API integrations, there are high chances of getting randomly generated numbers from the content served by them.

Another approach to exploit a random number is using the fact that Math.random() only returns numbers between 0 and 1 with 16 decimal places. This means that there are only 10^16 possible values that Math.random() can return. This is a very small space compared to the space of possible OTPs. if your OTP has 6 digits, there are 10^6 possible values. This visualizer shows that there is a pattern to the numbers generated. Using it, the possibilities can be reduced by 30%. Therefore, if you can guess or brute-force some of the digits of the OTP, you can reduce the space of possible values and increase your chances of finding the correct OTP.

Generating a Cryptographic Random Number in NodeJS

As mentioned previously, cryptographic random numbers are non-deterministic because they depend on the physical factors of a system. Every programming language can access those factors using low-level OS kernel calls.

NodeJS provides its inbuilt crypto module, which we can use to generate randomBytes and then convert them to a number. These random bytes are cryptographic and purely random in nature. The generated number can easily be truncated to the exact number of digits we want in OTP.

import * as crypto from 'crypto';
const num = parseInt(crypto.randomBytes(3).toString('hex'), 16)
// num.toString().slice(0,4)  // truncate to 4 digits

NodeJS 14.10+ provides another function from crypto to generate a random number in a given min-max range.

crypto.randomInt(1001, 9999)

Even after knowing the vulnerability of Math.random() and finding a more secure way to generate a random number cryptographically, we still remain with the same question from the beginning. Why do we have to go to such lengths to use a library to generate OTP when all we have to do is write a one-liner?

Before answering this questions, let's take a look at what is the inconvenience faced while handling and storing an OTP. The problem with using the above method to generate OTPs is that you have to store them in the database in order to verify them later. Storing the OTP in the database is not a good practice for the following reasons:

  1. Storing OTPs in the database creates a lot of garbage data that has to be cleaned up periodically. OTP means a one-time password that can expire after a single use. It can also expire if not used for a specific duration or a new OTP is requested without using the previous one. This mainly adds unnecessary overhead to the database operations for maintaining valid OTPs while also consuming storage space.
  2. Storing OTPs in the database poses a security risk if the database is compromised. An attacker who gains access to the database can read the OTPs and use them to bypass the authentication or verification process. This can lead to account takeover, identity theft, or fraud.
  3. Storing OTPs in the database makes them vulnerable to replay attacks. A replay attack is when an attacker intercepts an incoming valid OTP and uses it again before it expires. This can allow the attacker to perform unauthorised actions or access sensitive information.

What do the OTP libraries do differently?

The OTP libraries use different algorithms and techniques to generate and verify OTPs that behave similarly to a Cryptographic random OTP, while also removing the overhead to store the OTP in a database.

There are mainly two types of OTP implementation techniques.

HOTP

HOTP stands for HMAC-based One-Time Password. It is an algorithm that generates an OTP based on a secret key and a counter. The secret key is a random string that is shared between the server and the user. The counter is an integer that increments every time an OTP is generated or verified.

The algorithm works as follows:

• The server and the user generate the same OTP by applying a cryptographic hash function, such as SHA-1, to the concatenation of the secret key and the counter.
• The server and the user truncate the hash value to obtain a fixed-length OTP, usually 6 or 8 digits.
• The user sends the OTP to the server for verification.
• The server compares the OTP with its own generated OTP and verifies it if they match.
• The server and the user increment their counters by one.

HOTP est principalement utilisé dans l'authentification matérielle basée sur des jetons comme Yubikey. Yubikey est essentiellement une clé matérielle programmée que vous pouvez connecter physiquement à votre ordinateur ou téléphone. Au lieu de recevoir un code par SMS ou par e-mail, vous pouvez simplement appuyer sur un bouton de Yubikey pour vous vérifier et vous authentifier.

Les avantages du HOTP sont :

• Il ne nécessite pas de stocker l'OTP dans la base de données, car il peut être généré et vérifié à la volée.
• Il ne repose pas sur des nombres pseudo-aléatoires, car il utilise une fonction de hachage cryptographique imprévisible et irréversible.
• Il résiste aux attaques par rejeu, car chaque OTP n'est valide qu'une seule fois.

Les inconvénients du HOTP sont :

• Cela nécessite une synchronisation entre le serveur et les compteurs de l'utilisateur. S'ils sont désynchronisés en raison de retards du réseau, d'erreurs de transmission ou de perte de l'appareil, la vérification échouera.
• Il reste valide tant qu'un HOTP nouvellement généré n'est pas utilisé, cela peut constituer une vulnérabilité.
• Cela nécessite un moyen sécurisé de distribuer et de stocker les clés secrètes. Si les clés secrètes sont divulguées ou volées, les OTP peuvent être compromis.

TOTP

TOTP signifie Time-based One-Time Password. Il s'agit d'un algorithme qui génère un OTP basé sur une clé secrète, un horodatage et une époque.

  • La clé secrète est une chaîne aléatoire partagée entre le serveur et l'utilisateur. Il peut être créé de manière unique pour chaque utilisateur en générant SHA1( "secretvalue" + user_id ) .
  • L'horodatage est un entier qui représente l'heure actuelle en secondes
  • L'époque est la durée pendant laquelle l'algorithme générera le même résultat. généralement, il est conservé entre 30 sec et 1 min.

L'algorithme fonctionne comme suit :
• Le serveur décide d'une clé secrète pour l'utilisateur et la partage sur un support tel que les applications Authenticator.
• Le serveur peut générer directement un OTP et l'envoyer à l'utilisateur par mail ou SMS, ou il peut demander à l'utilisateur d'utiliser un authentificateur pour générer un OTP à l'aide de la clé partagée.
• L'utilisateur peut envoyer directement l'OTP reçu par mail ou SMS ou le générer dans l'application d'authentification en cas de 2FA dans une fenêtre de temps fixe.
• Le serveur compare l'OTP avec son propre OTP généré et le vérifie s'ils sont suffisamment proches dans la plage horaire.

Les avantages du TOTP sont :

• Il ne nécessite pas de stocker l'OTP dans la base de données, car il peut être généré et vérifié à la volée.
• Il ne repose pas sur des nombres pseudo-aléatoires, car il utilise une fonction de hachage cryptographique imprévisible et irréversible.
• Il résiste aux attaques par rejeu, car chaque OTP n'est valide que pour une courte période de temps.
• Il ne nécessite pas de synchronisation entre le serveur et les horodatages de l'utilisateur. Tant qu'ils disposent d'horloges raisonnablement précises, ils peuvent générer et vérifier les OTP de manière indépendante.

Les inconvénients du TOTP sont :

• Cela nécessite un moyen sécurisé de distribuer et de stocker les clés secrètes. Si les clés secrètes sont divulguées ou volées, les OTP peuvent être compromis.
• Cela nécessite une source de temps fiable à la fois pour le serveur et pour l'utilisateur. Si leurs horloges sont faussées ou falsifiées, la vérification échouera.
• Le serveur doit tenir compte de la dérive temporelle ou du retard dans le traitement des requêtes, il doit donc maintenir une époque légèrement supérieure à celle du client.

Conclusion

Grâce à notre petit voyage de recherche sur l'OTP, nous avons appris que Math.random() peut être prédit, exploité et rejoué. Nous avons également appris que stocker les OTP dans la base de données n'est pas une bonne pratique.

TOTP peut générer des OTP sécurisés et efficaces, et peut également les vérifier. Il peut générer un OTP hors ligne comme en ligne, ne nécessite ni synchronisation ni stockage et résiste aux attaques par relecture. Cela résout ainsi la plupart de nos préoccupations liées aux meilleures pratiques, à la sécurité et à la fiabilité.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn