Random 8 character string generator

Eight characters from a 62-symbol alphabet: 47.6 bits, generated in your browser and never sent anywhere.

G
More options
up to 10,000

Constraints

What 47.6 bits resists

Eight alphanumeric characters give 8 x log2(62) = 47.634 bits over a keyspace of 62^8 = 218,340,105,584,896. That is roughly four thousand times the six-character space, and it is still not enough to stand on its own against offline attack.

The time an attacker needs is set by the hash far more than by the length. Averaged over the keyspace, 47.6 bits falls in about 8 minutes against unsalted MD5 on one GPU at 220.6 GH/s, about an hour against SHA2-256 at 28.35 GH/s, and about 1,450 years against bcrypt at cost 12, whose rate is roughly 2,381 hashes per second. Same string, same entropy, seven orders of magnitude between the endpoints.

It also sits below the 64-bit threshold at which NIST SP 800-63B-4 stops requiring rate limiting, so an 8-character secret is never safe standing alone at the verifier.

Eight characters stopped being a password minimum

The standard moved. NIST SP 800-63B-4 states that verifiers and CSPs SHALL require passwords used as a single-factor authentication mechanism to be a minimum of 15 characters in length. Eight survives only inside multi-factor authentication, where a second factor is carrying the load. The same document says that other composition requirements for passwords SHALL NOT be imposed, which retires the uppercase-plus-digit-plus-symbol rule most login forms still enforce.

PCI DSS v4.0.1 requirement 8.3.6, in force since 31 March 2025, asks for 12 characters containing both numeric and alphabetic characters. Two current standards, two different minimums, and neither of them is 8. If you are generating a password, the 12-character and 16-character pages are where to go.

Appendix A of SP 800-63B-4 names machine-generated random passwords as a more effective mitigation than composition rules, which is a fair summary of why a generator exists at all. The critique NIST makes of entropy scoring applies to passwords a human invented, where the estimate is guesswork. It does not apply to a uniform machine draw, where L x log2(N) is exact.

Verbatim, NIST SP 800-63B-4: "Verifiers and CSPs SHALL require passwords that are used as a single-factor authentication mechanism to be a minimum of 15 characters in length."

Where eight characters is genuinely right

Eight is usually a length something else chose for you: a CHAR(8) column in a schema nobody is going to migrate, a voucher format already printed, a filename suffix, a test fixture that has to match an existing pattern. Those are real constraints and an 8-character random string is the correct answer to them.

It is also a sensible size for values that are identifiers rather than secrets: build tags, temporary directory names, cache-busting suffixes, seeded test data. Nothing there is guessed by an attacker, so the only question is duplicate risk, and the answer is comfortable at this scale. The chance of a repeat passes 1% at about 2.1 million strings and 50% at about 17.4 million.

The failure case is using 8 characters for something that authenticates: a password, an API key, a password reset token, a webhook secret. In every one of those the value is exposed to guessing at a rate you do not control, and 47.6 bits is short by a wide margin.

Doing this in your own code

JavaScript
const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";  // 62 characters

function randomString(length = 8) {
  // Largest multiple of 62 that fits in a uint32. Anything at or above it
  // is discarded, which is what keeps the mapping uniform.
  const limit = Math.floor(2 ** 32 / ALPHABET.length) * ALPHABET.length;
  const buf = new Uint32Array(1);
  let out = "";
  for (let i = 0; i < length; i++) {
    do { crypto.getRandomValues(buf); } while (buf[0] >= limit);
    out += ALPHABET[buf[0] % ALPHABET.length];
  }
  return out;
}

randomString();  // 8 characters

Without the rejection step, 2^32 does not divide evenly by 62 and the first four characters of the alphabet come up slightly more often.

Python 3.6+
import secrets
import string

ALPHABET = string.ascii_letters + string.digits  # 62 characters

"".join(secrets.choice(ALPHABET) for _ in range(8))

secrets.choice goes through randbelow, which rejects out-of-range values internally. random.choice is unbiased as well, but it runs on the Mersenne Twister and must not be used here.

Go
import (
	"crypto/rand"
	"math/big"
)

const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

func RandomString(n int) (string, error) {
	b := make([]byte, n)
	max := big.NewInt(int64(len(alphabet)))
	for i := range b {
		v, err := rand.Int(rand.Reader, max)
		if err != nil {
			return "", err
		}
		b[i] = alphabet[v.Int64()]
	}
	return string(b), nil
}

RandomString(8)

crypto/rand.Int already does rejection sampling, so the result is uniform. math/rand is not a substitute at any size.

PHP 7+
function random_string(int $length): string {
    $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $max = strlen($alphabet) - 1;
    $out = '';
    for ($i = 0; $i < $length; $i++) {
        $out .= $alphabet[random_int(0, $max)];
    }
    return $out;
}

random_string(8);

random_int is CSPRNG-backed and unbiased. rand(), mt_rand() and array_rand() are none of those things.

Java
import java.security.SecureRandom;

static final String ALPHABET =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static final SecureRandom RNG = new SecureRandom();

StringBuilder sb = new StringBuilder(8);
for (int i = 0; i < 8; i++) {
    sb.append(ALPHABET.charAt(RNG.nextInt(ALPHABET.length())));
}
sb.toString();

nextInt(bound) rejects and redraws when the bound does not divide the range evenly, so no bias is introduced here.

C# / .NET
using System.Security.Cryptography;

const string Alphabet =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

var chars = new char[8];
for (int i = 0; i < chars.Length; i++)
{
    chars[i] = Alphabet[RandomNumberGenerator.GetInt32(Alphabet.Length)];
}
string value = new string(chars);

RandomNumberGenerator.GetInt32 is unbiased. System.Random is not cryptographic and is the wrong class for this job.

Shell
# Linux and macOS. LC_ALL=C stops tr rejecting bytes outside the locale.
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 8; echo

# openssl, if you want 8 hexadecimal characters instead
# (4 bytes = 8 hex characters = 32 bits, exactly)
openssl rand -hex 4

tr -dc discards bytes outside the set rather than folding them into it, so the one-liner is uniform. /dev/urandom is the kernel CSPRNG on both platforms.

Questions

Is an 8-character password still acceptable?

Under NIST SP 800-63B-4, only inside multi-factor authentication. The single-factor minimum is 15 characters and it is written as a SHALL. PCI DSS v4.0.1 sets its own floor at 12. If you control the requirement, generate 16 characters and stop thinking about it.

How long does it take to crack 47.6 bits?

It depends entirely on the hash. Averaged over the keyspace: roughly 8 minutes against unsalted MD5 on one GPU, about an hour against SHA2-256, about 1,450 years against bcrypt at cost 12. Any single number quoted without naming a hash function and a rate is not a real answer.

Does adding symbols make an 8-character string safe?

It helps and it does not fix it. Moving from 62 to 94 printable characters takes 8 characters from 47.63 to 52.44 bits, still below the 64-bit line NIST attaches rate limiting to. Two more characters buys more than the whole symbol set does.

Why do so many systems still require exactly 8 characters?

Because the requirement was written when 8 was the standard minimum and the fixed-width column behind it was never changed. It is a schema artefact, not a security position, and NIST SP 800-63B-4 explicitly moved away from it.

Are these strings unique?

They are independent draws, so uniqueness is probabilistic. Over 62^8 the chance of a repeat reaches 1% at about 2.1 million strings. If your use needs a guarantee, enforce it with a unique index and regenerate on conflict rather than relying on the odds.

Related generators