All Tools / Blog / Cara Membuat Password Acak yang Aman di JavaScript dan Python

Cara Membuat Password Acak yang Aman di JavaScript dan Python

3 min read

Kebanyakan generator password yang orang buat sendiri menggunakan Math.random() — dan itu tidak aman. Untuk password yang tahan serangan brute-force, kamu perlu generator angka acak yang aman secara kriptografi. Panduan ini menunjukkan cara yang benar.

Apa yang membuat password aman?

Dua faktor menentukan kekuatan password: panjang dan ukuran set karakter. Entropi (dalam bit) mengukur keduanya:

entropi = log2(ukuran_set_karakter ^ panjang)
        = panjang × log2(ukuran_set_karakter)

Target praktis:

  • 128 bit — aman untuk sebagian besar kegunaan
  • 80 bit — minimum untuk hal penting
  • < 40 bit — bisa dipecahkan dengan hardware konsumer
Jenis password Bit per karakter Panjang untuk 128-bit entropi
Huruf kecil saja (26 karakter) 4,7 28 karakter
Campuran huruf + angka (62 karakter) 5,95 22 karakter
ASCII cetak penuh (94 karakter) 6,55 20 karakter
Kata Diceware (7.776 kata) 12,9 10 kata

Password 20 karakter dengan huruf besar, kecil, angka, dan simbol memiliki ~128 bit entropi. Itu targetnya.

JavaScript — browser

Gunakan crypto.getRandomValues() — satu-satunya API yang benar untuk ini. Jangan pernah gunakan Math.random().

function generatePassword(length = 20, options = {}) {
    const {
        uppercase = true,
        lowercase = true,
        digits = true,
        symbols = true,
    } = options;

    let chars = '';
    if (uppercase) chars += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    if (lowercase) chars += 'abcdefghijklmnopqrstuvwxyz';
    if (digits)    chars += '0123456789';
    if (symbols)   chars += '!@#$%^&*()-_=+[]{}|;:,.<>?';

    if (!chars) throw new Error('Minimal satu set karakter harus diaktifkan');

    const array = new Uint32Array(length);
    crypto.getRandomValues(array);

    return Array.from(array, x => chars[x % chars.length]).join('');
}

console.log(generatePassword(20));
// "kT9!mP2#xQ7@rL5$nW8^"

JavaScript — Node.js

const crypto = require('crypto');

function generatePassword(length = 20) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
    const bytes = crypto.randomBytes(length);
    return Array.from(bytes, b => chars[b % chars.length]).join('');
}

console.log(generatePassword(24));
// "Xm9kQ!rL2nP@jT5vW8sZ#hK"

Python

Modul secrets Python (Python 3.6+) adalah alat yang tepat — menggunakan CSPRNG dari sistem operasi.

import secrets
import string

def generate_password(length: int = 20) -> str:
    alphabet = string.ascii_letters + string.digits + string.punctuation
    return ''.join(secrets.choice(alphabet) for _ in range(length))

print(generate_password(20))
# "k!T9mP2#xQ7@rL5$nW8^"

secrets.choice() memilih dari urutan menggunakan CSPRNG sistem operasi. Ini fungsi yang benar. Jangan gunakan random.choice() — modul random tidak aman secara kriptografi.

import secrets
import string

def generate_password(
    length: int = 20,
    uppercase: bool = True,
    lowercase: bool = True,
    digits: bool = True,
    symbols: bool = True,
) -> str:
    chars = ''
    required = []

    if uppercase:
        chars += string.ascii_uppercase
        required.append(secrets.choice(string.ascii_uppercase))
    if lowercase:
        chars += string.ascii_lowercase
        required.append(secrets.choice(string.ascii_lowercase))
    if digits:
        chars += string.digits
        required.append(secrets.choice(string.digits))
    if symbols:
        sym = '!@#$%^&*()-_=+[]{}|;:,.<>?'
        chars += sym
        required.append(secrets.choice(sym))

    if not chars:
        raise ValueError('Minimal satu set karakter harus diaktifkan')

    remaining = length - len(required)
    pool = required + [secrets.choice(chars) for _ in range(remaining)]
    secrets.SystemRandom().shuffle(pool)
    return ''.join(pool)

print(generate_password(24))

Ini menjamin minimal satu karakter dari setiap set yang diaktifkan, lalu mengacak posisinya.

Command line

# macOS/Linux — openssl
openssl rand -base64 20

# Hanya alfanumerik
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 20

# Linux — /dev/urandom
cat /dev/urandom | tr -dc 'a-zA-Z0-9!@#$%^&*' | head -c 20; echo

# Python one-liner
python3 -c "import secrets, string; print(''.join(secrets.choice(string.ascii_letters + string.digits + '!@#\$%^&*') for _ in range(20)))"

Yang TIDAK boleh digunakan

  • Math.random() (JavaScript) — menggunakan PRNG, bukan CSPRNG. Bisa diprediksi.
  • random.random() / random.choice() (Python) — masalah yang sama.
  • Sistem yang meng-hash timestamp atau username — tidak acak.
  • Password di bawah 12 karakter — terlalu pendek untuk hal sensitif.

Ringkasan

  • Gunakan crypto.getRandomValues() di browser JavaScript, crypto.randomBytes() di Node.js.
  • Gunakan secrets.choice() di Python — bukan random.choice().
  • Gunakan openssl rand dari command line.
  • Target 20+ karakter dengan set karakter campuran untuk ~128 bit entropi.
  • Math.random() tidak aman untuk password — jangan gunakan untuk keperluan kriptografi.