Banyak developer yang bingung milih antara SHA256 dan bcrypt buat nyimpen password. Padahal kedua algoritma ini punya tujuan berbeda dan salah pilih bisa berakibat fatal buat keamanan aplikasi. Artikel ini bakal ngebahas perbedaan mendasar, kapan pake yang mana, dan kenapa bcrypt jauh lebih aman buat password hashing.
Perbedaan Fundamental: Tujuan Desain
Sebelum masuk ke detail teknis, penting buat paham filosofi desain kedua algoritma ini.
| Aspek | SHA256 | bcrypt |
|---|---|---|
| Tujuan utama | Data integrity, checksum | Password hashing |
| Kecepatan | Cepat (by design) | Lambat (by design) |
| Salt | Tidak built-in | Built-in otomatis |
| Adaptive | Tidak (fixed algorithm) | Ya (adjustable cost) |
| Resistensi brute-force | Rendah | Tinggi |
Key Insight: SHA256 dibuat buat verifikasi integritas data (file checksum, digital signature), sementara bcrypt dibuat khusus buat melindungi password dari brute-force attacks.
1. Cara Kerja dan Karakteristik
SHA256 (Secure Hash Algorithm 256-bit)
SHA256 adalah cryptographic hash function dari keluarga SHA-2 yang dirancang oleh NSA. Outputnya selalu 256-bit (64 karakter hex) regardless input size.
# Contoh hash SHA256
echo -n "password123" | sha256sum
# Output: ef92b768b6b9e1b6b5e1e3c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8
# Karakteristik:
# - Selalu 64 karakter hex
# - Deterministic: input sama = output sama
# - Cepat: jutaan hash per detik di GPU modern
Karakteristik SHA256:
- Deterministic: Hash yang sama selalu menghasilkan output yang sama
- One-way: Tidak bisa reverse dari hash ke original input
- Avalanche effect: Perubahan 1 bit input mengubah sebagian besar output
- Collision resistant: Sulit menemukan dua input dengan hash sama
bcrypt (Blowfish Crypt)
bcrypt adalah adaptive hashing algorithm yang berbasis cipher Blowfish. Outputnya tidak fixed length dan mengandung salt serta cost factor.
# Contoh hash bcrypt
$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
# Format: $2b$[cost]$[salt+hash]
# - $2b$: Algorithm identifier
# - 12: Cost factor (2^12 = 4096 iterasi)
# - 22 karakter: Salt (16 byte base64 encoded)
# - 31 karakter: Hash (24 byte base64 encoded)
Karakteristik bcrypt:
- Salted: Setiap hash punya salt random yang unik
- Adaptive: Cost factor bisa dinaikin seiring meningkatnya hardware
- Slow by design: Sengaja lambat buat hindari brute-force
- Self-contained: Semua parameter (salt, cost) ada di dalam hash string
2. Perbandingan Kecepatan: Mengapa Itu Penting
Kecepatan adalah perbedaan paling kritis. SHA256 terlalu cepat buat password hashing.
Benchmark Kecepatan
| Hardware | SHA256 | bcrypt (cost 12) |
|---|---|---|
| CPU Modern | ~1 juta hash/detik | ~50-100 hash/detik |
| GPU (RTX 4090) | ~10 miliar hash/detik | ~500-1000 hash/detik |
| FPGA/ASIC | ~100+ miliar hash/detik | Sulit diakselerasi |
import hashlib
import bcrypt
import time
password = b"test_password"
# SHA256 speed test
start = time.time()
for _ in range(100000):
hashlib.sha256(password).hexdigest()
sha_time = time.time() - start
# bcrypt speed test
start = time.time()
for _ in range(100):
bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))
bcrypt_time = time.time() - start
print(f"SHA256 100k hashes: {sha_time:.2f}s")
print(f"bcrypt 100 hashes: {bcrypt_time:.2f}s")
print(f"Perbandingan: SHA256 ~{int((sha_time/100000)/(bcrypt_time/100))}x lebih cepat")
Implikasi Keamanan
Skenario serangan brute-force:
| Password | SHA256 (GPU) | bcrypt (cost 12) |
|---|---|---|
password | < 1 detik | ~2-3 hari |
Password123 | ~1 menit | ~3-6 bulan |
P@ssw0rd!2024 | ~1 hari | ~50+ tahun |
Kesimpulan: SHA256 terlalu cepat buat password. Attacker bisa coba miliaran kombinasi per detik, sementara bcrypt membatasi ke ratusan percobaan per detik.
3. Perlindungan terhadap Rainbow Table
Rainbow table adalah precomputed table buat reverse hash. Ini ancaman besar buat password hashing.
SHA256: Rentan tanpa Salt
import hashlib
# Tanpa salt, hash yang sama selalu identik
common_passwords = ["password", "123456", "qwerty", "admin"]
# Attacker bisa precompute:
rainbow_table = {hashlib.sha256(p.encode()).hexdigest(): p for p in common_passwords}
# Ketika database bocor:
leaked_hash = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
if leaked_hash in rainbow_table:
print(f"Password found: {rainbow_table[leaked_hash]}")
# Output: Password found: password
Solusi manual untuk SHA256 (tidak recommended):
import hashlib
import os
# Tambahkan salt manual (tetap kurang aman)
salt = os.urandom(32) # 256-bit salt
password = b"user_password"
hash = hashlib.sha256(salt + password).hexdigest()
# Tapi tetap cepat dan tidak adaptive!
bcrypt: Proteksi Otomatis
import bcrypt
# Setiap hash punya salt unik yang beda-beda
hash1 = bcrypt.hashpw(b"password", bcrypt.gensalt())
hash2 = bcrypt.hashpw(b"password", bcrypt.gensalt())
print(hash1) # $2b$12$abc...
print(hash2) # $2b$12$xyz... (berbeda!)
# Rainbow table tidak efektif karena setiap entry unik
4. Use Case: Kapan Pake Apa?
Gunakan SHA256 untuk:
1. File Integrity / Checksum
# Verifikasi download tidak corrupt
sha256sum ubuntu-22.04.iso
# Compare dengan hash official
# Verify file integrity setelah transfer
sha256sum -c checksum.txt
2. Digital Signatures
import hashlib
import hmac
# HMAC dengan SHA256 untuk API authentication
secret_key = b"api_secret_key"
message = b"request_payload"
signature = hmac.new(secret_key, message, hashlib.sha256).hexdigest()
# Kirim signature bersama request untuk verifikasi integrity
3. Blockchain / Cryptocurrency
# Bitcoin mining menggunakan double SHA256
import hashlib
def double_sha256(data):
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
4. Certificate Fingerprinting
# SSL certificate fingerprint
openssl x509 -in cert.pem -noout -sha256 -fingerprint
Gunakan bcrypt untuk:
1. Password Storage (User Authentication)
import bcrypt
def register_user(email, password):
# Hash password sebelum simpan ke DB
hashed = bcrypt.hashpw(
password.encode('utf-8'),
bcrypt.gensalt(rounds=12)
)
save_to_database(email, hashed)
def login_user(email, password):
stored_hash = get_hash_from_db(email)
return bcrypt.checkpw(
password.encode('utf-8'),
stored_hash.encode('utf-8')
)
2. API Key Hashing
# API key disimpan sebagai hash, bukan plaintext
api_key = generate_random_key() # "ak_live_12345..."
hashed_key = bcrypt.hashpw(api_key.encode(), bcrypt.gensalt())
# Simpan hashed_key di DB, kirim api_key sekali ke user
3. Secure Token Hashing
# Reset password token, email verification token
token = generate_secure_token()
hashed_token = bcrypt.hashpw(token.encode(), bcrypt.gensalt(rounds=10))
# Simpan hashed_token di DB, kirim token ke email/user
5. Implementasi yang Salah vs Benar
❌ Salah: Pake SHA256 buat Password
import hashlib
class BadAuthSystem:
def hash_password(self, password):
# JANGAN LAKUKAN INI!
return hashlib.sha256(password.encode()).hexdigest()
def verify_password(self, password, stored_hash):
return self.hash_password(password) == stored_hash
# Masalah:
# 1. Tidak ada salt -> rainbow table attack
# 2. Terlalu cepat -> brute force mudah
# 3. Tidak adaptive -> tidak bisa upgrade security
✅ Benar: Pake bcrypt buat Password
import bcrypt
class SecureAuthSystem:
def hash_password(self, password: str) -> str:
"""Hash password dengan bcrypt"""
return bcrypt.hashpw(
password.encode('utf-8'),
bcrypt.gensalt(rounds=12)
).decode('utf-8')
def verify_password(self, password: str, stored_hash: str) -> bool:
"""Verify password dengan secure comparison"""
return bcrypt.checkpw(
password.encode('utf-8'),
stored_hash.encode('utf-8')
)
def needs_rehash(self, stored_hash: str, new_cost: int = 14) -> bool:
"""Check apakah perlu rehash dengan cost lebih tinggi"""
# Ambil cost dari stored hash
cost = int(stored_hash.split('$')[2])
return cost < new_cost
6. Alternatif Modern: Argon2
Selain bcrypt, ada algoritma terbaru yang direkomendasikan oleh PHC (Password Hashing Competition): Argon2.
| Fitur | bcrypt | Argon2id |
|---|---|---|
| Memory hard | ❌ Tidak | ✅ Ya |
| GPU resistant | ⚠️ Sedang | ✅ Tinggi |
| Side-channel resistant | ⚠️ Partial | ✅ Ya |
| Winner PHC 2015 | ❌ | ✅ |
| Recommendation | ✅ Good | ✅ Better |
# Argon2 (lebih aman dari bcrypt untuk aplikasi baru)
import argon2
ph = argon2.PasswordHasher(
time_cost=3, # Iterations
memory_cost=65536, # 64 MB
parallelism=1
)
hash = ph.hash("user_password")
ph.verify(hash, "user_password") # True
Rekomendasi: Untuk aplikasi baru, pertimbangkan Argon2id. Untuk sistem existing, bcrypt masih sangat aman dan lebih widely supported.
7. Checklist Keputusan
Gunakan diagram keputusan ini buat milih algoritma:
Apakah data yang di-hash adalah password/user credential?
├── YA → Gunakan bcrypt (atau Argon2)
│ └── Butuh adaptive cost? → bcrypt ✅
│ └── Butuh memory-hard? → Argon2 ✅
└── TIDAK → Apakah butuh kecepatan tinggi?
├── YA → SHA256 (data integrity, checksum)
└── TIDAK → Pertimbangkan use case spesifik
8. Kesalahan Umum yang Harus Dihindari
1. Double Hashing (SHA256 + bcrypt)
# ❌ SALAH - Tidak menambah keamanan, malah bisa weaken
hashed = bcrypt.hashpw(sha256(password).digest(), salt)
# ✅ BENAR - bcrypt saja sudah cukup
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
2. Custom Crypto
# ❌ SALAH - Jangan bikin algoritma sendiri!
def my_hash(password):
return sha256(password + "my_secret_salt")
# ✅ BENAR - Pake library teruji
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
3. Salt yang Tidak Cukup Random
# ❌ SALAH - Salt statis atau predictable
salt = "my_app_name_2024" # Jangan!
# ✅ BENAR - Random cryptographically secure
salt = bcrypt.gensalt() # 16 byte random
Kesimpulan
| Kriteria | Pemenang | Keterangan |
|---|---|---|
| Password hashing | bcrypt | Lambat, salted, adaptive |
| File integrity | SHA256 | Cepat, deterministic |
| Digital signatures | SHA256 | Standar industri |
| Future-proofing | Argon2 | Memory-hard, PHC winner |
Aturan emas:
- Password/user credentials = bcrypt (atau Argon2)
- Data integrity/checksum = SHA256
- Jangan pernah pake SHA256 buat password storage
- Jangan pernah pake bcrypt buat large data hashing
Pemilihan algoritma yang tepat adalah fondasi keamanan aplikasi. Salah pilih bisa membuat data pengguna rentan meski sistem lainnya sudah aman. Stay secure dan pilih tools yang tepat untuk job yang tepat