Att välja identifierare: UUID, korta ID och de som läcker information
Använd en UUID v4 för allt internt, en v7 när identifieraren är primärnyckel i en stor tabell, och en kort kod ur ett begränsat alfabet när en människa ska läsa den högt. Löpande heltal är det alternativ du ska undvika för allt som är publikt.
UUID-versionerna som spelar roll
En UUID är 128 bitar. Fyra bär versionen och två varianten, så ingen version har alla 128 att spendera.
| Version | Vad den innehåller | Använd den när |
|---|---|---|
| v1 | 60-bitars tidsstämpel, 14-bitars klocksekvens, 48-bitars nod-ID (MAC-adressen) | Endast äldre data |
| v3 / v5 | En MD5- eller SHA-1-hash av en namnrymd och ett namn | Deterministiska ID behövs |
| v4 | 122 slumpbitar, inget annat | Standardvalet, när ingenting ska gå att härleda |
| v7 | 48-bitars millisekundstämpel, sedan 74 slumpbitar | Nycklar där insättningsordningen spelar roll |
v1 är den varnande. Den bäddar in skapelsetiden och, i de flesta implementationer, MAC-adressen för maskinen som gjorde den, vilket är hur sådana identifierare bidrog till att spåra upphovsmannen till Melissa-viruset 1999. v7, standardiserad i RFC 9562 år 2024, publicerar skapelsetiden med flit: både dess funktion och dess pris.
Frågan om kollisioner
En UUID v4 har 122 slumpbitar, så det finns 2^122 av dem, ungefär 5,3 x 10^36. Det som spelar roll är födelsedagsgränsen, inte rymdens storlek: sannolikheten att två av n värden sammanfaller är ungefär n i kvadrat delat med 2^123. En biljon genererade UUID bär omkring en chans på tio biljoner för en dubblett, och en chans som en slantsingling kräver omkring 2,7 x 10^18 värden, ungefär 85 år vid en miljard per sekund.
"Inget praktiskt bekymmer" är ändå inte "omöjligt", och glappet ligger aldrig i aritmetiken. Dubbletter kommer från generatorn: ett fast frö, en virtuell maskin som klonats med sin entropipool, en containeravbildning som levereras med sparat PRNG-tillstånd. Unikheten tillhör slumpkällan, inte formatet, så behåll unikhetsvillkoret på kolumnen.
Ordning, indexlokalitet och läckage
Slumpmässiga identifierare sprids ut. I ett B-trädsindex hamnar varje insättning på en slumpmässig lövsida, så arbetsmängden är hela indexet i stället för dess högra kant, cacheträffarna sjunker och sidor delas. En nyckel som stiger över tid lägger till på ett enda ställe och håller samma fåtal sidor varma. Det är därför v7 och ULID finns; ULID är 48 bitar millisekundstämpel plus 80 slumpbitar, skrivna som 26 sorterbara tecken i Crockfords base32.
Priset är förutsägbarhet: ett tidsordnat ID publicerar när dess post skapades, så en handfull avslöjar registreringstakt och lugna timmar. Om det spelar roll, använd v4 och betala indexkostnaden.
Löpande heltal går längre. /invoices/1041 säger att du har utfärdat omkring tusen fakturor, och två ID med en veckas mellanrum ger din tillväxttakt. Värre är att en angripare kan begära 1040. Om servern returnerar den posten för att den finns och anroparen är inloggad, utan att kontrollera vem som äger den, är det ett fel i åtkomstkontrollen, katalogiserat som en osäker direkt objektreferens. Ett ogissbart ID är ingen behörighetskontroll, men det hindrar någon från att vandra igenom tabellen.
Slugar är också identifierare, och läcker ingenting om volym när de byggs riktigt: accenter avlägsnade, gemener, skiljetecken sammandragna till bindestreck, precis som Slug Generator gör. Håll en slug stabil efter publicering; att ändra den bryter inkommande länkar.
Korta ID, alfabet och längd
Varje tecken i en slumpmässig kod är värt log2 av alfabetets storlek: 5,95 bitar för base62, 5 för base32, 4 för hexadecimalt. Längd och alfabet bestämmer kollisionssannolikheten för en given volym.
| Längd (base62) | Distinkta värden | Bitar | Kollisionsrisk inom 1 miljard ID |
|---|---|---|---|
| 8 | 2,2 x 10^14 | 43,7 | Så gott som säker |
| 10 | 8,4 x 10^17 | 59,5 | Omkring 45 % |
| 12 | 3,2 x 10^21 | 71,5 | Omkring 1 på 6 500 |
| 16 | 4,8 x 10^28 | 95,3 | Omkring 1 på 100 miljarder |
Det förutsätter att varje tecken är oberoende slumpmässigt; ett prefix som inv_ tillför noll bitar.
För allt en människa läser är base62 fel alfabet. 0 och O, 1 och l och I är avskrivningsfel som bara väntar på att hända, och en skiftlägeskänslig kod överlever inte ett telefonsamtal. Crockfords base32 stryker I, L, O och U och accepterar båda skiftlägena vid inmatning, vilket är värt det extra tecknet.
Var slumpbitarna kommer ifrån
Math.random() är ingen kryptografisk källa. V8 implementerar den med xorshift128+, vars interna tillstånd går att återskapa ur en kort följd av utdata, varefter varje framtida värde är förutsägbart. Utmärkt för en demoblandning eller en platshållare. Fel för en sessionsidentifierare, en API-nyckel, en återställningslänk eller en token.
// Browsers, Node 19+, Deno and Bun
const id = crypto.randomUUID();
const bytes = new Uint8Array(16);
crypto.getRandomValues(bytes);
Annorstädes: crypto.randomBytes i Node, secrets.token_urlsafe i Python, crypto/rand i Go, SecureRandom i Java, random_bytes i PHP. UUID Generator producerar kryptografiskt slumpmässiga v4-värden och Password Generator använder samma webbläsar-API; Random Numbers är till för sampling, inte för hemligheter.
En fälla när du bygger eget: att mappa en slumpmässig byte på ett alfabet med 62 tecken med % 62 snedvrider mot de första åtta tecknen; använd förkastningssampling.
Platshållar- och exempeldata
Lorem ipsum är förvanskad Cicero, och det överlever för att det är oläsbart: text som ser ut som språk utan att vara språk låter en layout bedömas på form och radlängd i stället för på sina meningar, vilket är vad Lorem Ipsum-generatorn producerar. Byt in realistisk text före godkännandet, eftersom platshållarlatinet döljer det överflöd en riktig rubrik kommer att orsaka.
Påhittade data behöver en enda regel: de får aldrig kunna misstas för det äkta.
- Kortnummer hämtas från en betalleverantörs publicerade testintervall, eller faller rakt igenom Luhn-kontrollen. Ett slumpmässigt 16-siffrigt nummer som klarar Luhn tillhör någon.
- Personidentifierare använder reserverade intervall. Amerikanska Social Security-nummer som börjar på 000, 666 eller 900 till 999 utfärdas aldrig.
- Använd
example.comoch dess syskon, reserverade av RFC 2606, och dokumentationsblocket 192.0.2.0/24.
Testdata når produktion oftare än väntat: ett seed-skript riktat mot fel databas, en platshållare kvarglömd i en e-postmall som skickas till hela listan. Falska poster ska se uppenbart falska ut, så att en människa fångar en innan supporten agerar på den.
QR-koder i korthet
En QR-kod är ett rutnät av moduler, version 1 till 40, från 21x21 upp till 177x177. Nyttolastens längd styr versionen, och vid en fast tryckt storlek betyder en högre version mindre moduler, vilket kräver bättre tryck och en närmare skanning. Förkorta URL:en innan du matar in den i QR Code Generator, och notera att alfanumeriskt läge bara hanterar versaler, så HTTPS://EXAMPLE.COM kodas mindre än formen med gemener.
Felkorrigeringen har fyra nivåer och återställer ungefär 7 % (L), 15 % (M), 25 % (Q) och 30 % (H) av en skadad kod. Redundans kostar kapacitet, så en högre nivå trycker samma nyttolast in i en tätare version. M är det vanliga standardvalet; välj Q eller H för finstilt tryck, böjda ytor eller en logotyp mitt över, vilket fungerar just för att redundansen absorberar den.
Två fysiska krav avgör om en kod går att skanna. Den tysta zonen är en fri marginal på fyra moduler runt om, som avkodaren använder för att hitta gränsen, så en kod som ligger dikt an mot en ram eller ett fotografi misslyckas ofta. Kontrasten måste vara genuint mörkt mot genuint ljust: ljusblått på vitt är ett vanligt misslyckande, och många avkodare vägrar inverterade koder.