Membedah keamanan Rails: perlindungan bawaan terhadap SQLi, XSS, CSRF, dan mass assignment, security headers, serta praktik audit dan hardening aplikasi

Setelah di episode 17 kalian bisa melihat ke dalam aplikasi lewat log, episode 18 membahas topik yang tidak boleh ditunda: keamanan. Rails memblokir banyak serangan secara default — tetapi hanya jika kalian memahami apa yang dilindungi dan di mana harus tetap waspada.
Mengapa episode ini penting? Karena aplikasi web adalah permukaan serangan publik: siapa pun di internet bisa mencoba menginjeksi SQL, mencuri session, atau mengirim form palsu. Kabar baiknya, Rails dirancang dengan keamanan sebagai default — episode ini menjelaskan mengapa default itu bekerja dan apa saja yang harus kalian jaga agar tetap aman.
SQLi terjadi saat input pengguna disisipkan mentah ke query SQL. Contoh rentan:
Post.where("title = '#{params[:title]}'")
# user kirim: x' OR 1=1 --Rails melindungi dengan query parameterized — Active Record selalu mem-escape input:
Post.where(title: params[:title])
Post.where("title = ?", params[:title]) # placeholder ?
Post.where("title ILIKE ?", "%#{params[:q]}%") # placeholder pada inputAturan emas: gunakan ? placeholder untuk semua input; jangan pernah interpolasi user input ke SQL string. Hindari execute/sanitize_sql manual kecuali benar-benar diperlukan.
XSS terjadi saat input user dirender sebagai HTML tanpa escape. Rails meng-escape secara default: semua <%= %> di-escape. Hati-hati hanya saat kalian sengaja menonaktifkannya:
<%= @post.body %> <!-- AMAN: di-escape -->
<%= raw @post.body %> <!-- RENTAN: di-render mentah -->
<%= sanitize @post.body %> <!-- SANITIZE: HTML diizinkan tapi difilter -->raw / html_safe menonaktifkan escape — jangan dipakai untuk user input.sanitize mengizinkan HTML tertentu dengan whitelist tag — pakai untuk rich text (dengan rails-html-sanitizer yang selalu di-update).CSRF menipu browser korban yang sudah login agar mengirim request berbahaya. Rails memblokirnya dengan token CSRF:
<%= csrf_meta_tags %>Semua form yang dibuat form_with otomatis menyertakan authenticity_token; protect_from_forgery (default aktif) memverifikasi token pada request non-GET. Yang harus kalian jaga:
skip_forgery_protection tanpa alasan.Note
Pola yang benar: aplikasi web dengan session cookie → CSRF protection aktif. API yang memakai token di header → CSRF protection tidak diperlukan (tidak ada cookie yang di-forge). Mencampur keduanya butuh kehati-hatian ekstra.
Episode 8 sudah membahas ini dalam-dalam — ringkasnya: params.expect/permit memastikan hanya kolom yang di-whitelist yang bisa di-assign. Ingat kembali konsekuensinya:
# RENTAN: user bisa set admin=true via payload manual
@user.update(params[:user])
# AMAN: hanya field whitelist
@user.update(params.expect(user: [:name, :email]))Jika tabel user punya kolom admin, payload POST /users dengan user[admin]=true akan mengeksekusi privilege escalation tanpa strong params.
Rails 8 menyediakan header keamanan di config/initializers/:
Rails.application.config.content_security_policy do |policy|
policy.default_src :self
policy.font_src :self, :https
policy.img_src :self, :https, :data
policy.object_src :none
policy.script_src :self
policy.style_src :self, :https
endHeader yang dilindungi Rails:
| Header | Fungsi |
|---|---|
X-Frame-Options | Mencegah clickjacking |
X-Content-Type-Options | Mencegah MIME sniffing |
Content-Security-Policy (CSP) | Membatasi sumber script/asset |
Referrer-Policy | Mengontrol info yang dikirim via referrer |
Cek header app kalian dengan curl -I http://localhost:3000 atau tool securityheaders.com.
Checklist rutin yang menjaga app tetap aman:
bundle exec brakeman di CI.bundle audit untuk CVE (episode 19).authorize.config.action_dispatch.default_headers bersih.bundle exec brakeman -qBrakeman melaporkan kategori risiko dengan level severity — jadikan hasilnya checklist perbaikan, bukan dokumen yang dibiarkan menumpuk.
raw / html_safe pada user input — XSS kembali hidup; gunakan sanitize untuk rich text.skip_forgery_protection tanpa pemikiran — CSRF token hilang; jaga default aktif."WHERE id = #{params[:id]}"; selalu ? placeholder.render json: user polos — kolom sensitif (password_digest) bocor; gunakan serializer.Episode 18 membekali kalian keamanan Rails: parameterized queries melawan SQLi, escaping otomatis melawan XSS, CSRF tokens melawan request forgery, strong params melawan mass assignment, security headers, serta audit rutin dengan Brakeman.
Inti yang harus dibawa pulang:
? placeholder, jangan interpolasi input ke SQL.<%= %> otomatis escape; hindari raw pada user input.protect_forgery default; jangan skip tanpa alasan.params.expect adalah garis pertahanan terakhir.bundle audit + review authorization.Di episode 19 selanjutnya kita akan membedah CVE & dependency management — contoh CVE-2026-66066 di Active Storage/vips, security releases Rails, dan praktik update rutin dengan bundle audit. Sampai jumpa di episode 19!