[B]

Blog

  • A Stronger Username and Password Regex

    While setting up a Grav CMS website, a stronger username and password regex was in order. The username default regex for the installation is ^[a-z0-9_-]{3,16}$ all lower case letters, digits, dashes, underscores, and must be 3–16 characters. The default password regex is (?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,} one number, one upper case, one lower case, and 8 or more characters.

    Username: ^[a-z0-9_-]{3,16}$
    Password: (?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}

    The defaults are simply unacceptable. Too many websites are being hacked, and making a stronger regex is a simple way to make it harder to for the basement hacker to crack.

    So, I did a bit of research, fed my requirements into my handy know-it-all (AI), tested it out, and voilà — a shinny new regex is born. 🙂

    The Final Regex Code

    Username:

    ^[a-z][a-z0-9_-]{4,16}$

    Password:

    ^[a-z](?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?!.*(.)(\1))(?!.*0[oO]|.*[oO]0)(?!.*1[lLI]|.*[lLI]1)(?!.*5[sS]|.*[sS]5)(?!.*2[zZ]|.*[zZ]2)(?!.*8[bB]|.*[bB]8)(?!.*6[gG]|.*[gG]6)(?!.*9[gG]|.*[gG]9)(?!.*c[CƆ]|.*[CƆ]c)(?!.*a[@A]|.*[@A]a)(?!.*m.rn|.*rn.*m).{11,}$

    The only difference in the regex codes above is the username must be 5–15 characters long, and the password must be at least 12 characters.

    And for all the code junkies out there who stumble across this post, here are the technical bits:

    Regex Breakdown

    Username Regex:

    ^[a-z][a-z0-9_-]{2,15}$

    ComponentPurpose
    ^Start of string anchor
    [a-z]Username must start with a lowercase letter
    [a-z0-9_-]{2,15}Remaining characters must be lowercase letters, digits, underscores, or dashes
    Ensures total length is 3–16 characters
    $End of string anchor

    Password Regex:

    ^[a-z](?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?!.*(.)(\1))(?!.*0[oO]|.*[oO]0)(?!.*1[lLI]|.*[lLI]1)(?!.*5[sS]|.*[sS]5)(?!.*2[zZ]|.*[zZ]2)(?!.*8[bB]|.*[bB]8)(?!.*6[gG]|.*[gG]6)(?!.*9[gG]|.*[gG]9)(?!.*c[CƆ]|.*[CƆ]c)(?!.*a[@A]|.*[@A]a)(?!.*m.rn|.*rn.*m).{11,}$

    ComponentPurpose
    ^Start of string
    [a-z]Password must start with a lowercase letter
    (?=.*[a-z])Requires at least one lowercase character
    (?=.*[A-Z])Requires at least one uppercase character
    (?=.*\d)Requires at least one number
    (?!.*(.)(\1))No identical consecutive characters
    Confusable (homoglyph) detection
    (?!.*0[oO]|.*[oO]0)Forbid 0 with o/O
    (?!.*1[lLI]|.*[lLI]1)Forbid 1 with l/L/I
    (?!.*5[sS]|.*[sS]5)Forbid 5 with s/S
    (?!.*2[zZ]|.*[zZ]2)Forbid 2 with z/Z
    (?!.*8[bB]|.*[bB]8)Forbid 8 with b/B
    (?!.*6[gG]|.*[gG]6)Forbid 6 with g/G
    (?!.*9[gG]|.*[gG]9)Forbid 9 with g/G
    (?!.*c[CƆ]|.*[CƆ]c)Forbid c with C/Ɔ
    (?!.*a[@A]|.*[@A]a)Forbid a with A/@
    (?!.*m.rn|.*rn.*m)Special case: forbid m next to homoglyph sequence rn
    .{11,}After consuming the first letter, require ≥11 more characters → total length ≥12
    $End of string

    Homoglyph Pairs Covered

    Homoglyph PairRule
    0 / o / O(?!.*0[oO]|.*[oO]0)
    1 / l / L / I(?!.*1[lLI]|.*[lLI]1)
    5 / s / S(?!.*5[sS]|.*[sS]5)
    2 / z / Z(?!.*2[zZ]|.*[zZ]2)
    8 / b / B(?!.*8[bB]|.*[bB]8)
    6 / g / G(?!.*6[gG]|.*[gG]6)
    9 / g / G(?!.*9[gG]|.*[gG]9)
    c / C / Ɔ(?!.*c[CƆ]|.*[CƆ]c)
    a / A / @(?!.*a[@A]|.*[@A]a)
    m / rn(?!.*m.rn|.*rn.*m)

    Test Cases

    InputResultReason
    john_doe✅ MATCHValid username
    abc123✅ MATCHValid username
    a-b_c✅ MATCHValid username
    ab❌ NO MATCHToo short (<3 chars)
    Aabc❌ NO MATCHMust start with lowercase
    aPassword123456✅ MATCHValid password
    aA1bcdefghijk✅ MATCHMeets all password rules
    aAA1bbbbbbbb❌ NO MATCHConsecutive repeated characters
    aPassword000❌ NO MATCHContains 0 and o
    apP1mRnsecure❌ NO MATCHContains both m and rn

    Summary

    Username Regex Enforces:

    1. Starts with a lowercase letter
    2. Contains only lowercase letters, digits, underscores, and dashes
    3. Total length 3–16
    4. No homoglyph or repetition checks (not needed)

    Password Regex Enforces:

    1. Starts with a lowercase letter
    2. Contains uppercase, lowercase, and digits
    3. 12+ characters long
    4. No identical consecutive characters
    5. Homoglyph/confusable pairs disallowed
    6. m/rn visual‑collision disallowed

  • Time Has Passed

    After a long hiatus, it’s time for a new web site. It will be a collaborative experiment, with myself and my new AI named Tom. Tom’s posts will always be tagged.

    On with the experiment!