Episode ini membahas penanganan data yang aman: encoding UTF-8 dan transkoding string untuk mencegah encoding errors, validasi dan sanitasi input, strong params di Rails, hashing password dengan bcrypt, serta prinsip least privilege.

Episode 15 menutup celah umum dengan tools keamanan. Episode 16 ini melangkah lebih dalam: menangani data dengan benar sejak masuk sampai disimpan. Dua tema besar dibahas — encoding string dan validasi input — plus hashing password serta prinsip least privilege.
Encoding yang salah adalah sumber error aneh seperti ArgumentError: invalid byte sequence in UTF-8 yang sering muncul di aplikasi multi-bahasa. Validasi input mencegah data cacat masuk ke database. Hashing password memastikan data sensitif tetap aman bila database bocor.
Setiap string di Ruby membawa informasi encoding. Metode String#encoding mengembalikan labelnya, dan String#valid_encoding? mengecek apakah byte yang terkandung sesuai dengan label tersebut:
teks = "halo"
puts teks.encoding
puts teks.valid_encoding?puts teks.encoding menampilkan encoding default file source. Ketika membaca file eksternal atau response HTTP, jangan asumsikan UTF-8 — selalu cek dan sesuaikan encoding-nya.
Untuk mengubah byte dari satu encoding ke encoding lain, gunakan String#encode. Bila byte tidak valid, encode melempar exception, jadi tangkap dengan rescue atau paksa penggantian karakter:
latin = teks.encode("ISO-8859-1")
puts latin.encoding
teks.encode("UTF-8", invalid: :replace, undef: :replace)teks.encode("ISO-8859-1") menghasilkan string baru dalam encoding Latin-1. Opsi invalid: :replace mengganti byte yang tidak dikenal dengan karakter pengganti alih-alih melempar error. Untuk input web, pastikan meta charset dan header Content-Type menyatakan UTF-8 secara konsisten.
Validasi menjawab pertanyaan: apakah data ini bentuknya benar? Di model ActiveRecord, validasi dinyatakan deklaratif:
class Pengguna < ApplicationRecord
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :usia, numericality: { only_integer: true, greater_than: 0 }
endvalidates :email, presence: true memastikan email ada, dan format disesuaikan dengan pola email standar. numericality memastikan usia angka positif. Validasi di model adalah garis pertahanan pertama; tambahkan validasi di sisi client hanya untuk pengalaman pengguna, bukan keamanan.
Masih ada celah: parameter mass assignment. Penyerang bisa mengirim field tersembunyi seperti admin: true. Rails menutupnya dengan strong params — whitelist field yang boleh di-assign:
def params_pengguna
params.require(:pengguna).permit(:email, :nama, :usia)
endparams.require(:pengguna).permit(:email, :nama, :usia) hanya mengizinkan tiga field tersebut masuk ke model. Field lain, termasuk admin atau role, diabaikan. Prinsip ini berlaku juga untuk parameter query di aplikasi non-Rails: ambil eksplisit setiap field yang kalian butuhkan.
Menyimpan password mentah adalah pelanggaran terbesar. Simpan hanya hash-nya menggunakan bcrypt — algoritma yang lambat secara sengaja untuk memperlambat brute force. Rails sudah menyertakan bcrypt melalui has_secure_password; untuk project lain tambahkan gem:
gem install bcrypt
bundle add bcryptbundle add bcrypt menambahkan gem ke Gemfile dan meng-install-nya. Di kode, hash password saat registrasi dan verifikasi saat login:
require "bcrypt"
hash = BCrypt::Password.create("rahasia123")
puts BCrypt::Password.new(hash) == "rahasia123"BCrypt::Password.create("rahasia123") menghasilkan hash dengan salt acak otomatis. Verifikasi dilakukan dengan membandingkan ulang, bukan dengan mendekripsi — bcrypt satu arah. Jangan pernah menulis log yang berisi password atau token.
Least privilege berarti memberikan akses seminimal mungkin yang dibutuhkan untuk bekerja. Di database, buat akun aplikasi yang tidak punya hak DROP atau TRUNCATE. Di kode, jangan berikan kemampuan penuh kepada input pengguna, dan selalu verifikasi otorisasi sebelum operasi sensitif:
def hapus_tugas(id)
tugas = Tugas.find_by(id: id, pemilik_id: current_user.id)
raise "Tidak berhak" unless tugas
tugas.destroy
endtugas.destroy hanya berjalan ketika pemilik cocok dengan pengguna yang sedang login. Pola scoping seperti ini mencegah IDOR, insecure direct object reference. Terapkan least privilege juga pada secrets, IAM, dan service account.
Tip
Audit rutin: cek daftar grant database, key environment yang tidak terpakai, dan user yang sudah nonaktif. Privilege yang mengendap adalah risiko yang tidak terpantau.
Inti yang harus dibawa pulang:
String#encoding dan valid_encoding? adalah gerbang pertama menangani teks.String#encode dengan opsi penggantian mencegah crash pada byte tak valid.Di episode 17 kita berpindah dari keamanan ke performa: mengaktifkan YJIT dengan --yjit, mengukur waktu dengan Benchmark, memakai ruby-prof untuk menemukan hotspot, serta memahami GC.stat dan GC.config. Aplikasi yang aman kini akan kita buat cepat juga.