[{"data":1,"prerenderedAt":539},["ShallowReactive",2],{"blog-password-security-best-practices":3},{"id":4,"title":5,"body":6,"category":526,"date":527,"description":528,"extension":529,"meta":530,"navigation":531,"path":532,"readingTime":533,"seo":534,"stem":535,"tool":536,"updated":537,"__hash__":538},"blog\u002Fblog\u002Fpassword-security-best-practices.md","Password Security Best Practices for Developers",{"type":7,"value":8,"toc":504},"minimark",[9,13,16,21,24,35,155,162,166,171,192,196,203,207,210,237,244,248,252,255,259,262,351,355,358,364,367,381,384,388,394,400,406,410,414,428,432,446,453,457,492,496],[10,11,12],"p",{},"Passwords remain the most common authentication mechanism on the internet. Despite decades of alternatives — biometrics, hardware keys, passkeys — most systems still rely on passwords as their primary or fallback authentication method. Getting password security right protects your users; getting it wrong makes headlines.",[10,14,15],{},"This guide covers password generation, storage, and validation from a developer's perspective.",[17,18,20],"h2",{"id":19},"password-entropy","Password Entropy",[10,22,23],{},"Entropy measures how unpredictable a password is. Higher entropy means more guesses required to crack it. Entropy is measured in bits:",[25,26,31],"pre",{"className":27,"code":29,"language":30},[28],"language-text","Entropy = log2(possible_characters ^ length)\n","text",[32,33,29],"code",{"__ignoreMap":34},"",[36,37,38,57],"table",{},[39,40,41],"thead",{},[42,43,44,48,51,54],"tr",{},[45,46,47],"th",{},"Password type",[45,49,50],{},"Characters",[45,52,53],{},"Length",[45,55,56],{},"Entropy",[58,59,60,75,89,102,116,129,142],"tbody",{},[42,61,62,66,69,72],{},[63,64,65],"td",{},"4-digit PIN",[63,67,68],{},"10",[63,70,71],{},"4",[63,73,74],{},"13 bits",[42,76,77,80,83,86],{},[63,78,79],{},"8 lowercase letters",[63,81,82],{},"26",[63,84,85],{},"8",[63,87,88],{},"38 bits",[42,90,91,94,97,99],{},[63,92,93],{},"8 mixed case + digits",[63,95,96],{},"62",[63,98,85],{},[63,100,101],{},"48 bits",[42,103,104,107,110,113],{},[63,105,106],{},"12 mixed + symbols",[63,108,109],{},"95",[63,111,112],{},"12",[63,114,115],{},"79 bits",[42,117,118,121,123,126],{},[63,119,120],{},"16 mixed + symbols",[63,122,109],{},[63,124,125],{},"16",[63,127,128],{},"105 bits",[42,130,131,134,137,139],{},[63,132,133],{},"4 random words (diceware)",[63,135,136],{},"7,776",[63,138,71],{},[63,140,141],{},"51 bits",[42,143,144,147,149,152],{},[63,145,146],{},"6 random words (diceware)",[63,148,136],{},[63,150,151],{},"6",[63,153,154],{},"78 bits",[10,156,157,161],{},[158,159,160],"strong",{},"Minimum recommendation:"," 72+ bits of entropy for important accounts. This means at least 12 characters with mixed case, digits, and symbols — or 6 random words.",[17,163,165],{"id":164},"generating-strong-passwords","Generating Strong Passwords",[167,168,170],"h3",{"id":169},"what-makes-a-password-strong","What makes a password strong?",[172,173,174,180,186],"ol",{},[175,176,177,179],"li",{},[158,178,53],{}," — the single most important factor. Each additional character multiplies the search space",[175,181,182,185],{},[158,183,184],{},"Randomness"," — must be generated by a cryptographic random source, not chosen by a human",[175,187,188,191],{},[158,189,190],{},"Uniqueness"," — one password per service, never reused",[167,193,195],{"id":194},"why-humans-are-bad-at-passwords","Why humans are bad at passwords",[10,197,198,199,202],{},"Humans choose predictable patterns: dictionary words, dates, keyboard patterns (qwerty), substitutions (p@ssw0rd). These patterns are in every password cracker's dictionary. A \"clever\" human-chosen password like ",[32,200,201],{},"Tr0ub4dor&3"," has about 28 bits of entropy — far less than a random 12-character string.",[167,204,206],{"id":205},"cryptographic-randomness","Cryptographic randomness",[10,208,209],{},"Password generators must use a cryptographic random number generator (CSPRNG):",[211,212,213,219,225,231],"ul",{},[175,214,215,216],{},"Browser: ",[32,217,218],{},"crypto.getRandomValues()",[175,220,221,222],{},"Node.js: ",[32,223,224],{},"crypto.randomBytes()",[175,226,227,228],{},"Python: ",[32,229,230],{},"secrets.token_hex()",[175,232,233,234],{},"Linux: ",[32,235,236],{},"\u002Fdev\u002Furandom",[10,238,239,240,243],{},"Never use ",[32,241,242],{},"Math.random()"," or language-level pseudo-random generators — they are predictable.",[17,245,247],{"id":246},"storing-passwords-server-side","Storing Passwords (Server-Side)",[167,249,251],{"id":250},"never-store-plaintext-passwords","Never store plaintext passwords",[10,253,254],{},"This should be obvious, but breaches at major companies prove it is not. Never store passwords in plaintext, Base64, or reversible encryption.",[167,256,258],{"id":257},"use-a-password-hashing-function","Use a password hashing function",[10,260,261],{},"Password hashing functions are designed to be slow — they take 100ms+ per hash, making brute-force attacks impractical:",[36,263,264,277],{},[39,265,266],{},[42,267,268,271,274],{},[45,269,270],{},"Algorithm",[45,272,273],{},"Recommended?",[45,275,276],{},"Notes",[58,278,279,292,305,317,330,341],{},[42,280,281,286,289],{},[63,282,283],{},[158,284,285],{},"Argon2id",[63,287,288],{},"Best choice",[63,290,291],{},"Winner of the Password Hashing Competition. Memory-hard, resistant to GPU and ASIC attacks",[42,293,294,299,302],{},[63,295,296],{},[158,297,298],{},"bcrypt",[63,300,301],{},"Good",[63,303,304],{},"Widely available, CPU-hard. 72-byte input limit",[42,306,307,312,314],{},[63,308,309],{},[158,310,311],{},"scrypt",[63,313,301],{},[63,315,316],{},"Memory-hard and CPU-hard",[42,318,319,324,327],{},[63,320,321],{},[158,322,323],{},"PBKDF2",[63,325,326],{},"Acceptable",[63,328,329],{},"Available everywhere but GPU-parallelizable. Use with SHA-256 and high iteration count",[42,331,332,335,338],{},[63,333,334],{},"MD5",[63,336,337],{},"Never",[63,339,340],{},"Fast hash, trivially cracked",[42,342,343,346,348],{},[63,344,345],{},"SHA-256",[63,347,337],{},[63,349,350],{},"Fast hash, not designed for passwords",[167,352,354],{"id":353},"always-salt-passwords","Always salt passwords",[10,356,357],{},"A salt is a random value added to each password before hashing:",[25,359,362],{"className":360,"code":361,"language":30},[28],"hash = argon2id(password + salt)\nstore: salt + hash\n",[32,363,361],{"__ignoreMap":34},[10,365,366],{},"Salting prevents:",[211,368,369,375],{},[175,370,371,374],{},[158,372,373],{},"Rainbow tables"," — precomputed hash lookups",[175,376,377,380],{},[158,378,379],{},"Identical hashes"," — two users with the same password get different hashes",[10,382,383],{},"Most password hashing libraries handle salting automatically (bcrypt, Argon2id include the salt in the output).",[167,385,387],{"id":386},"configuration-recommendations","Configuration recommendations",[10,389,390,393],{},[158,391,392],{},"Argon2id:"," memory=64MB, iterations=3, parallelism=1 (adjust based on your server's resources)",[10,395,396,399],{},[158,397,398],{},"bcrypt:"," cost factor=12 (adjust upward as hardware improves)",[10,401,402,405],{},[158,403,404],{},"PBKDF2:"," iterations=600,000+ with SHA-256",[17,407,409],{"id":408},"password-validation-rules","Password Validation Rules",[167,411,413],{"id":412},"do","Do",[211,415,416,419,422,425],{},[175,417,418],{},"Require a minimum length (12+ characters recommended by NIST SP 800-63B)",[175,420,421],{},"Check against a list of known breached passwords (the Have I Been Pwned API provides this)",[175,423,424],{},"Allow all printable Unicode characters, including spaces",[175,426,427],{},"Allow passwords up to at least 128 characters",[167,429,431],{"id":430},"do-not","Do not",[211,433,434,437,440,443],{},[175,435,436],{},"Require specific character classes (uppercase, digit, symbol) — NIST recommends against this",[175,438,439],{},"Impose a maximum length under 64 characters",[175,441,442],{},"Force periodic password changes — NIST found this leads to weaker passwords",[175,444,445],{},"Use password hints or security questions — these leak information",[10,447,448,449,452],{},"NIST's research shows that composition rules (must include uppercase, digit, symbol) lead to predictable patterns like ",[32,450,451],{},"Password1!",". Length and randomness are more effective than complexity rules.",[17,454,456],{"id":455},"common-mistakes","Common Mistakes",[172,458,459,465,474,480,486],{},[175,460,461,464],{},[158,462,463],{},"Logging passwords"," — never log request bodies that contain passwords, even in error logs",[175,466,467,473],{},[158,468,469,470],{},"Comparing with ",[32,471,472],{},"=="," — use constant-time comparison to prevent timing attacks",[175,475,476,479],{},[158,477,478],{},"Rolling your own crypto"," — use established libraries (bcrypt, Argon2id) rather than implementing hashing yourself",[175,481,482,485],{},[158,483,484],{},"Rate limiting failures"," — without rate limiting, an attacker can brute-force the login endpoint",[175,487,488,491],{},[158,489,490],{},"Password in URL"," — query parameters appear in server logs, browser history, and referrer headers",[17,493,495],{"id":494},"generate-passwords","Generate Passwords",[10,497,498,503],{},[499,500,502],"a",{"href":501},"\u002Ftools\u002Fpassword-generator","StackCache Password Generator"," creates strong passwords with cryptographic browser randomness. Configure length, character classes, and exclusion rules — everything runs locally with no server.",{"title":34,"searchDepth":505,"depth":505,"links":506},2,[507,508,514,520,524,525],{"id":19,"depth":505,"text":20},{"id":164,"depth":505,"text":165,"children":509},[510,512,513],{"id":169,"depth":511,"text":170},3,{"id":194,"depth":511,"text":195},{"id":205,"depth":511,"text":206},{"id":246,"depth":505,"text":247,"children":515},[516,517,518,519],{"id":250,"depth":511,"text":251},{"id":257,"depth":511,"text":258},{"id":353,"depth":511,"text":354},{"id":386,"depth":511,"text":387},{"id":408,"depth":505,"text":409,"children":521},[522,523],{"id":412,"depth":511,"text":413},{"id":430,"depth":511,"text":431},{"id":455,"depth":505,"text":456},{"id":494,"depth":505,"text":495},"Security","2026-09-08","Learn how to generate, store, and validate passwords securely. Covers entropy, hashing algorithms, salting, and common mistakes in password systems.","md",{},true,"\u002Fblog\u002Fpassword-security-best-practices",7,{"title":5,"description":528},"blog\u002Fpassword-security-best-practices","password-generator",null,"p4HX1cih5Se2nv7tPvO7lJL5nkhsS7mmkLZZFlrSYo8",1788868139561]