search
HomeWeb Front-endJS TutorialWhy do we use OTP libraries when we can just do Math.random()

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

One-time passwords (OTPs) are widely used for authentication and verification purposes in various applications and services. A server usually generates them and sends them to the user via SMS, email, or other channels. The user then enters the OTP to confirm their identity or perform an action.

I got a task where we had to implement OTP-based verification in Node JS. Before integrating something like this, I am sure most of us developers/engineers look on the Internet for best practices, tutorials, recent technical trends, and problems other major software systems face during their implementations. So I did it, and the thing that most attracted my attention was libraries like otp-lib, and otp-generator, whose only function was to generate an OTP. The rest of the tasks like sending it over an SMS or email still need to be done by other means. The first question that comes to mind after knowing that such libraries exist is why 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:

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

In this blog post, I will explain what I learned during our small research for OTP generators, why using Math.random() to generate OTPs is a bad idea, what are other ways to generate an OTP, and why a library should be used for such a task?

Types of random numbers

There are mainly two types of random numbers:

  • Pseudo-Random Numbers (PRN)
  • Cryptographic Random Numbers (CRN).

Pseudo-Random Numbers

Pseudo-random numbers are generated by an algorithm that takes an initial value, called a seed, and produces a sequence of numbers that appear to be random. However, the algorithm is deterministic, meaning that if you know the seed and the algorithm, you can predict the next number in the sequence. Javascript's Math.random() and Python's random.randInt() are an example of a pseudo-random number generator.

Cryptographic Random Numbers

Cryptographic random numbers are generated by a process that is unpredictable and cannot be reproduced or guessed. They are usually based on some physical phenomenon, such as atmospheric noise, thermal noise, or quantum effects.

How Math.random() works?

Different Javascript engines behave a little differently when generating a random number, but it all essentially comes down to a single algorithm XorShift128+.

XorShift is a deterministic algorithm, which uses addition as a faster non-linear transformation solution. Compared to its peers, which use multiplication, this algorithm is faster. It also has less chance of failure than Mersenne Twister (used by Python's random module)

The algorithm takes in two state variables, applies some XOR and shift on them, and returns the sum of the updated state variables which is an Integer. The states are generally seeded using the system clock because that is a good source for a unique number.

An implementation of XOR shift plus in javascript looks like this:

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

The returned integer is converted to a double using OR operation with a constant. You can find the detailed implementation on chrome source code.

How to predict a random number generated by Math.random()

Predicting the outcome of Math.random() is hard, however, it is not completely impossible. Knowing the algorithm, you can easily regenerate the same random numbers if you know the values of state0 and state1.

Reverse engineering XorShift128+ Using a Z3 theorem prover you can find the value of state0 and state1 by providing 3 consecutive random numbers generated by a server.

The implementation of the Z3 solver can be found here.

Now the question comes how to get those 3 random numbers from a server. That's the hard part, and can be obtained in some of the following cases:

  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 is mostly used in hardware token-based authentication like Yubikey. Yubikey is basically a programmed hardware key that you can connect physically to your computer or phone. Instead of receiving a code from SMS, or email, you can just press a button on Yubikey to verify and authenticate yourself.

The advantages of HOTP are:

• It does not require storing the OTP in the database, as it can be generated and verified on the fly.
• It does not rely on pseudo-random numbers, as it uses a cryptographic hash function that is unpredictable and irreversible.
• It is resistant to replay attacks, as each OTP is valid only once.

The disadvantages of HOTP are:

• It requires synchronization between the server and the user's counters. If they are out of sync, due to network delays, transmission errors, or device loss, the verification will fail.
• It remains valid as long as a newly generated HOTP is not used, that can be a vulnerability.
• It requires a secure way to distribute and store the secret keys. If the secret keys are leaked or stolen, the OTPs can be compromised.

TOTP

TOTP stands for Time-based One-Time Password. It is an algorithm that generates an OTP based on a secret key, timestamp, and epoch.

  • The secret key is a random string that is shared between the server and the user. It can be created uniquely for each user by generating SHA1( "secretvalue" + user_id ) .
  • The timestamp is an integer that represents the current time in seconds
  • The epoch is the duration for which the algorithm will generate the same result. generally, it is kept between 30 sec - 1 min.

The algorithm works as follows:
• The server decides a secret key for the user and shares it over a medium like Authenticator apps.
• The server can directly generate an OTP and send it to the user by mail or SMS, or it can ask the user to use an Authenticator to generate an OTP using the shared key.
• The user can directly send the OTP received by mail or SMS or can generate it in the authenticator app in case of 2FA in a fixed time window.
• The server compares the OTP with its own generated OTP and verifies it if they are close enough in the epoch time range.

The advantages of TOTP are:

• It does not require storing the OTP in the database, as it can be generated and verified on the fly.
• It does not rely on pseudo-random numbers, as it uses a cryptographic hash function that is unpredictable and irreversible.
• It is resistant to replay attacks, as each OTP is valid only for a short period of time.
• It does not require synchronisation between the server and the user's timestamps. As long as they have reasonably accurate clocks, they can generate and verify OTPs independently.

The disadvantages of TOTP are:

• It requires a secure way to distribute and store the secret keys. If the secret keys are leaked or stolen, the OTPs can be compromised.
• It requires a reliable source of time for both the server and the user. If their clocks are skewed or tampered with, the verification will fail.
• The server has to consider the time drift or delay in processing the requests, so it should maintain a slightly greater epoch than the client.

Conclusion

Through our little research journey on the OTP, we came to know that Math.random() can be predicted, exploited, and replayed. We also got to know that storing OTPs in the database is not a good practice.

TOTP can generate secure and efficient OTPs, and can also verify them. It can generate an OTP offline as well as online, does not require synchronization or storage, and is resistant to replay attacks. Thus it solves most of our concerns related to best practices, security, and reliability.

The above is the detailed content of Why do we use OTP libraries when we can just do Math.random(). For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Python vs. JavaScript: A Comparative Analysis for DevelopersPython vs. JavaScript: A Comparative Analysis for DevelopersMay 09, 2025 am 12:22 AM

The main difference between Python and JavaScript is the type system and application scenarios. 1. Python uses dynamic types, suitable for scientific computing and data analysis. 2. JavaScript adopts weak types and is widely used in front-end and full-stack development. The two have their own advantages in asynchronous programming and performance optimization, and should be decided according to project requirements when choosing.

Python vs. JavaScript: Choosing the Right Tool for the JobPython vs. JavaScript: Choosing the Right Tool for the JobMay 08, 2025 am 12:10 AM

Whether to choose Python or JavaScript depends on the project type: 1) Choose Python for data science and automation tasks; 2) Choose JavaScript for front-end and full-stack development. Python is favored for its powerful library in data processing and automation, while JavaScript is indispensable for its advantages in web interaction and full-stack development.

Python and JavaScript: Understanding the Strengths of EachPython and JavaScript: Understanding the Strengths of EachMay 06, 2025 am 12:15 AM

Python and JavaScript each have their own advantages, and the choice depends on project needs and personal preferences. 1. Python is easy to learn, with concise syntax, suitable for data science and back-end development, but has a slow execution speed. 2. JavaScript is everywhere in front-end development and has strong asynchronous programming capabilities. Node.js makes it suitable for full-stack development, but the syntax may be complex and error-prone.

JavaScript's Core: Is It Built on C or C  ?JavaScript's Core: Is It Built on C or C ?May 05, 2025 am 12:07 AM

JavaScriptisnotbuiltonCorC ;it'saninterpretedlanguagethatrunsonenginesoftenwritteninC .1)JavaScriptwasdesignedasalightweight,interpretedlanguageforwebbrowsers.2)EnginesevolvedfromsimpleinterpreterstoJITcompilers,typicallyinC ,improvingperformance.

JavaScript Applications: From Front-End to Back-EndJavaScript Applications: From Front-End to Back-EndMay 04, 2025 am 12:12 AM

JavaScript can be used for front-end and back-end development. The front-end enhances the user experience through DOM operations, and the back-end handles server tasks through Node.js. 1. Front-end example: Change the content of the web page text. 2. Backend example: Create a Node.js server.

Python vs. JavaScript: Which Language Should You Learn?Python vs. JavaScript: Which Language Should You Learn?May 03, 2025 am 12:10 AM

Choosing Python or JavaScript should be based on career development, learning curve and ecosystem: 1) Career development: Python is suitable for data science and back-end development, while JavaScript is suitable for front-end and full-stack development. 2) Learning curve: Python syntax is concise and suitable for beginners; JavaScript syntax is flexible. 3) Ecosystem: Python has rich scientific computing libraries, and JavaScript has a powerful front-end framework.

JavaScript Frameworks: Powering Modern Web DevelopmentJavaScript Frameworks: Powering Modern Web DevelopmentMay 02, 2025 am 12:04 AM

The power of the JavaScript framework lies in simplifying development, improving user experience and application performance. When choosing a framework, consider: 1. Project size and complexity, 2. Team experience, 3. Ecosystem and community support.

The Relationship Between JavaScript, C  , and BrowsersThe Relationship Between JavaScript, C , and BrowsersMay 01, 2025 am 12:06 AM

Introduction I know you may find it strange, what exactly does JavaScript, C and browser have to do? They seem to be unrelated, but in fact, they play a very important role in modern web development. Today we will discuss the close connection between these three. Through this article, you will learn how JavaScript runs in the browser, the role of C in the browser engine, and how they work together to drive rendering and interaction of web pages. We all know the relationship between JavaScript and browser. JavaScript is the core language of front-end development. It runs directly in the browser, making web pages vivid and interesting. Have you ever wondered why JavaScr

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools