Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Generate security tokens with a CSPRNG, never Math.random
Use crypto.randomBytes/randomUUID/getRandomValues for tokens, IDs, salts, nonces — never Math.random or timestamps.
Bad example
| 1 | // Predictable: Math.random is a non-cryptographic PRNG. |
| 2 | export function makeResetToken(): string { |
| 3 | return Math.random().toString(36).slice(2) + Date.now().toString(36); |
| 4 | } |
| 5 |
|
| 6 | // Same problem for 'unique' ids used as security boundaries. |
| 7 | export function makeApiKey(): string { |
| 8 | let key = ''; |
| 9 | for (let i = 0; i < 32; i += 1) { |
| 10 | key += Math.floor(Math.random() * 16).toString(16); |
| 11 | } |
| 12 | return key; |
| 13 | } |
Explanation (EN)
Math.random() is not cryptographically secure: its output is generated by a seeded, non-cryptographic algorithm (e.g. xorshift) whose internal state can be recovered from a few observed outputs, making future values predictable. Mixing in Date.now() adds almost no entropy because timestamps are guessable. Reset tokens, API keys, and session IDs built this way are brute-forceable or predictable.
Objašnjenje (HR)
Math.random() nije kriptografski siguran: izlaz generira sjemenom inicijaliziran, ne-kriptografski algoritam (npr. xorshift) cije se interno stanje moze rekonstruirati iz nekoliko promatranih izlaza, sto cini buduce vrijednosti predvidljivima. Dodavanje Date.now() gotovo da ne dodaje entropiju jer su vremenske oznake pogodljive. Reset tokeni, API kljucevi i ID-evi sesija izgradeni ovako su podlozni grubom napadu ili predvidljivi.
Good example
| 1 | import { randomBytes, randomUUID } from 'node:crypto'; |
| 2 |
|
| 3 | // 256 bits of CSPRNG entropy, URL-safe. |
| 4 | export function makeResetToken(): string { |
| 5 | return randomBytes(32).toString('base64url'); |
| 6 | } |
| 7 |
|
| 8 | export function makeApiKey(): string { |
| 9 | return `sk_${randomBytes(24).toString('hex')}`; |
| 10 | } |
| 11 |
|
| 12 | export function makeRequestId(): string { |
| 13 | return randomUUID(); // v4, CSPRNG-backed |
| 14 | } |
| 15 |
|
| 16 | // Browser/Edge runtime equivalent: |
| 17 | export function makeNonce(): string { |
| 18 | const bytes = new Uint8Array(16); |
| 19 | crypto.getRandomValues(bytes); |
| 20 | return btoa(String.fromCharCode(...bytes)); |
| 21 | } |
Explanation (EN)
crypto.randomBytes (Node) and crypto.getRandomValues (Web/Edge) draw from the OS CSPRNG and are unpredictable. randomUUID() is CSPRNG-backed v4. Use at least 128 bits of entropy for tokens (OWASP recommends >=128, prefer 256 for long-lived secrets) and encode as base64url/hex. This works the same way in Node, the browser, and Next.js Edge runtime.
Objašnjenje (HR)
crypto.randomBytes (Node) i crypto.getRandomValues (Web/Edge) crpe iz OS CSPRNG-a i nepredvidljivi su. randomUUID() je v4 utemeljen na CSPRNG-u. Koristi barem 128 bita entropije za tokene (OWASP preporuca >=128, radije 256 za dugotrajne tajne) i kodiraj kao base64url/hex. Radi jednako u Nodeu, pregledniku i Next.js Edge runtimeu.
Exceptions / Tradeoffs (EN)
Math.random is fine for non-security purposes: jitter/backoff, UI animation, sampling, test fixtures, picking a placeholder. The rule is about anything an attacker benefits from guessing.
Iznimke / Tradeoffi (HR)
Math.random je u redu za ne-sigurnosne svrhe: jitter/backoff, UI animacije, uzorkovanje, test fixture, odabir placeholdera. Pravilo se odnosi na sve sto napadacu koristi da pogodi.