Hari 10: MD5 ke Bcrypt, Pipeline Hijau Lagi
4 min read

Hari 10: MD5 ke Bcrypt, Pipeline Hijau Lagi

Hari kesepuluh 60 hari DevSecOps! Fix SAST findings — ganti MD5 ke bcrypt, hapus custom rule HTTP TLS, dan pipeline CI kembali hijau setelah 4 job semua pass.

devsecops
semgrep
sast
bcrypt
golang
remediation
60-days-challenge
Share

Dari Pipeline Merah ke Pipeline Hijau (Lagi)

Kemarin pipeline merah karena Semgrep nemuin 2 findings: MD5 yang gak aman dan HTTP server tanpa TLS. Hari ini tugasnya fix semua itu biar pipeline kembali hijau.

Ini repeat pattern yang udah kita lakuin di Day 7 (SCA remediation): scan → temukan masalah → fix → pipeline hijau. Tapi kali ini yang di-fix bukan dependensi, tapi kode yang kita tulis sendiri.

Fix 1: Ganti MD5 dengan bcrypt

Kode pkg/crypto/hash.go yang kemarin sengaja bikin pakai MD5, sekarang diganti bcrypt — industry standard buat password hashing:

// SEBELUM — insecure, MD5 is cryptographically broken
func HashPassword(password string) string {
    h := md5.Sum([]byte(password))
    return hex.EncodeToString(h[:])
}

// SESUDAH — secure, bcrypt with auto-salt and cost factor
func HashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    return string(bytes), err
}

func CheckPassword(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

Perhatikan signature berubah dari func(string) string jadi func(string) (string, error) — sekarang return error juga, yang cuma good practice di Go. Dan kita tambah fungsi CheckPassword() buat verifikasi hash.

Kenapa bcrypt dan bukan SHA-256?

  • bcrypt otomatis tambah salt — gak perlu manual
  • bcrypt punya cost factor yang bisa di-adjust — makin tinggi makin lambat buat brute force
  • SHA-256 cocok buat checksum dan data integrity, bukan password hashing
  • Di Go, golang.org/x/crypto/bcrypt udah ada sebagai dependency transitif dari gin

Fix 2: HTTP tanpa TLS

Untuk finding no-http-listen-without-tls di main.go, kita tentukan untuk accept sebagai warning. Kenapa?

  • HTTP server tanpa TLS itu expected untuk development environment
  • Di production, biasanya pakai reverse proxy (nginx, cloud load balancer) yang handle TLS termination
  • Force TLS di application level buat development itu lebih ribet daripada manfaatnya

Jadi kita hapus custom rule no-http-listen-without-tls dari .semgrep.yml. Built-in rules dari p/golang masih akan flag ini sebagai WARNING, tapi custom rules kita cuma focus ke yang critical.

Hasil: Pipeline Hijau

✅ Build & Test (Go 1.26) — success
✅ Secret Scan (Gitleaks) — success  
✅ SCA Scan (Trivy) — success (0 CVE)
✅ SAST Scan (Semgrep) — success (0 blocking findings)

4/4 job hijau. Dari pipeline merah kemarin karena SAST findings, sekarang semua clean.

Perbandingan Sebelum dan Sesudah

Aspek Sebelum (Day 09) Sesudah (Day 10)
MD5 hashing crypto/md5 (insecure) bcrypt (secure)
HTTP tanpa TLS Flagged sebagai WARNING Accepted untuk dev environment
Semgrep custom findings 2 (1 ERROR, 1 WARNING) 0
Semgrep built-in findings 2 (use-of-md5, use-tls) 1 (use-tls, accepted)
Pipeline status ❌ MERAH ✅ HIJAU
Trivy CVE 0 0

Lesson Learned

1. bcrypt itu standard untuk password hashing, bukan SHA-256. Bcrypt auto-salt, punya cost factor, dan secara khusus dirancang buat password. SHA-256 dirancang buat data integrity, bukan password. Pilih tool yang sesuai use case-nya.

2. Accept WARNING di dev environment itu valid. HTTP tanpa TLS di development itu common pattern. Yang penting di production pakai reverse proxy yang handle TLS. Gak semua finding harus di-fix — tapi semua harus di-dokumentasi kenapa diterima.

3. Function signature change itu aman kalau belum dipanggil. HashPassword cuma di-blank import, jadi mengubah return type dari string ke (string, error) gak merusak kode mana pun. Kalau udah dipakai di banyak tempat, signature change butuh refactor lebih besar.

4. Custom rules bisa di-adjust per project. Kita hapus rule no-http-listen-without-tls karena gak applicable buat development API server. Tapi rule no-md5-usage tetap dipertahankan karena MD5 emang gak boleh dipakai di project perbankan manapun.

5. Pull pattern makin jelas: scan → temukan → fix → hijau. Dari Day 5 sampai Day 10, kita udah lakuin cycle ini 3 kali: SCA (scan → temukan CVE → fix dependencies → hijau), SAST (scan → temukan insecure pattern → fix kode → hijau). Pattern-nya konsisten dan repeatable.

Kesimpulan

Hari ini pipeline kembali hijau — 4/4 job pass, 0 CVE, 0 blocking SAST findings. Dari MD5 yang deprecated ke bcrypt yang aman, dari pipeline merah ke pipeline hijau.

Yang penting dari remediasi ini: kita bukan cuma nge-fix kode, tapi juga nge-fix strategy. MD5 itu fundamentally broken buat password hashing — gak ada versi "yang aman" dari MD5. Satu-satunya jalan adalah ganti total ke algoritma yang benar. Sama kayak jwt-go di Day 07 — library deprecated gak bisa di-patch, harus diganti total.

Sekarang pipeline punya 4 lapis pertahanan yang semua hijau: build/test, secret scanning, SCA scanning, dan SAST scanning. Setiap push dan PR otomatis di-scan dari 4 sudut yang berbeda.

Besok lanjut ke Hari 11: AI-Assisted Code Audit — gunakan output Trivy dan Semgrep sebagai input buat AI analisis.

Repo: github.com/stayrelevantid/chalange-devsecops

Enjoyed this article? Share it!

Share

Diskusi & Komentar

Artikel Terkait