1 / 48
↑↓ SPACE PGUP/PGDN HOME/END
BAB 9

AUTENTIKASI, OTORISASI,
DAN KEAMANAN WEB

"Security is not a feature. It's a requirement."

Authentication

Verifikasi Identitas

Authorization

Kontrol Akses

Security

Defense in Depth

TUJUAN PEMBELAJARAN

Kompetensi Bab 9

  • Memahami perbedaan authentication dan authorization dengan analogi konkret
  • Membangun sistem autentikasi lengkap: signup, login, logout, password reset
  • Mengintegrasikan authentication dengan RLS dan RBAC
  • Mengidentifikasi dan mencegah XSS, CSRF, IDOR, dan kerentanan umum lainnya
  • Mengevaluasi output AI untuk security-critical code dengan Security Review Checklist
PETA POSISI

Dari Prototype ke Production-Ready

Di Bab 8, Task Manager bekerja — tetapi semua orang melihat data yang sama. user_id masih hardcoded. Tidak ada privacy, tidak ada security.

Bab 8: Hardcoded

Data accessible oleh siapa saja. user_id di-hardcode di code.

Bab 9: Secured

Real users, sessions, access control, dan defense-in-depth security.

Bab 10: Deployed

Production environment dengan HTTPS dan monitoring.

ARSITEKTUR BAB 8

Open Access: Tidak Ada Identifikasi User

Browser
Supabase Database
❌ Masalah 1

Semua data visible oleh siapa saja yang buka aplikasi.

❌ Masalah 2

user_id hardcoded — tidak ada konsep "milik saya" vs "milik orang lain".

❌ Masalah 3

RLS policies tidak berfungsi karena auth.uid() selalu NULL.

❌ Masalah 4

Tidak ada audit trail — tidak tahu siapa melakukan apa.

ARSITEKTUR BAB 9

Secured Multi-User: Layered Security

Browser
Auth Layer
JWT Token
Authz Layer
RLS + RBAC
Database
  • Authentication: Signup/Login → JWT token tersimpan di session
  • Authorization: Setiap request di-verify via RLS policies + role checks
  • Data Isolation: User hanya bisa akses data miliknya sendiri
  • Audit: Semua action tercatat dengan user ID dan timestamp
KONSEP FUNDAMENTAL

Authentication ≠ Authorization

AUTHENTICATION

"Siapa Anda?"

Verifikasi identitas user. Login dengan email + password, OAuth, biometric, dll.

Analogi: Menunjukkan ID card di pintu masuk gedung.

AUTHORIZATION

"Apa yang boleh Anda lakukan?"

Kontrol akses berdasarkan permissions. User A boleh edit, User B read-only.

Analogi: Access card menentukan ruangan mana yang boleh Anda masuki.

Authentication tanpa Authorization = pintu terbuka untuk semua orang yang punya ID. Authorization tanpa Authentication = tidak tahu siapa yang punya akses.

AUTH FLOW

Complete Authentication Flow

User Submit
Credentials
Verify Password
Hash
Generate
JWT Token
Store in
Session
Authenticated
Requests
  • Step 1: User submit email + password via HTTPS
  • Step 2: Server hash password dan compare dengan hash tersimpan
  • Step 3: Jika match, generate JWT token dengan user ID + metadata
  • Step 4: Token disimpan di httpOnly cookie atau localStorage
  • Step 5: Setiap request attach token di Authorization header
JWT (JSON WEB TOKEN)

Stateless Authentication Token

// JWT Structure: header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VyX2lkIjoiMTIzNDUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJleHAiOjE3MTE1MzYwMDB9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header

Algorithm (HS256, RS256) dan type (JWT).

Payload

User data: ID, email, roles, expiration time.

Signature

Hash dari header + payload + secret key. Prevent tampering.

⚠️ JWT payload is BASE64 encoded, NOT encrypted. Jangan taruh sensitive data (password, credit card).

BAGIAN 1

Supabase Auth: Built-in Authentication

  • Supabase menyediakan auth system lengkap out-of-the-box
  • Support email/password, OAuth (Google, GitHub), magic links, phone auth
  • Auto-generate auth.users table dengan user profiles
  • JWT token management dan session refresh otomatis
  • Email verification, password reset, rate limiting built-in

Tidak perlu build auth dari nol. Supabase handle complexity, Anda fokus di business logic.

SIGNUP IMPLEMENTATION

User Registration dengan Supabase

import { supabase } from '@/lib/supabase';

async function handleSignup(email, password) {
  const { data, error } = await supabase.auth.signUp({
    email: email,
    password: password,
    options: {
      emailRedirectTo: `${window.location.origin}/auth/confirm`
    }
  });

  if (error) {
    console.error('Signup error:', error.message);
    return;
  }

  // Supabase sends verification email
  alert('Check your email for verification link');
}
  • Password automatically hashed (bcrypt)
  • Email verification link dikirim otomatis
  • User tidak bisa login sampai email verified
LOGIN IMPLEMENTATION

User Authentication

async function handleLogin(email, password) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email: email,
    password: password
  });

  if (error) {
    console.error('Login error:', error.message);
    return;
  }

  // data.user contains user info
  // data.session contains JWT token
  console.log('Logged in as:', data.user.email);
  router.push('/dashboard');
}
Session Storage

Token tersimpan di localStorage (default) atau bisa customized ke httpOnly cookie.

Auto Refresh

Supabase client auto-refresh expired tokens sebelum expire.

LOGOUT & PASSWORD RESET

Session Termination dan Recovery

// LOGOUT
async function handleLogout() {
  const { error } = await supabase.auth.signOut();
  if (error) console.error('Logout error:', error.message);
  else router.push('/login');
}

// PASSWORD RESET
async function handlePasswordReset(email) {
  const { error } = await supabase.auth.resetPasswordForEmail(email, {
    redirectTo: `${window.location.origin}/auth/reset-password`
  });

  if (error) console.error('Reset error:', error.message);
  else alert('Check your email for reset link');
}
  • signOut() menghapus token dari storage dan invalidate session
  • Password reset link dikirim via email dengan expiration time
CURRENT USER

Mengakses Data User yang Login

import { useEffect, useState } from 'react';

function useAuth() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Get current user
    supabase.auth.getUser().then(({ data }) => {
      setUser(data.user);
    });

    // Listen to auth state changes
    const { data: authListener } = supabase.auth.onAuthStateChange(
      (event, session) => {
        setUser(session?.user ?? null);
      }
    );

    return () => authListener.subscription.unsubscribe();
  }, []);

  return user;
}

✓ Sekarang Anda punya user.id untuk replace hardcoded user_id di Bab 8!

PROTECTED ROUTES

Route Guards dengan Middleware

// middleware.js (Next.js App Router)
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs';
import { NextResponse } from 'next/server';

export async function middleware(req) {
  const res = NextResponse.next();
  const supabase = createMiddlewareClient({ req, res });

  const { data: { session } } = await supabase.auth.getSession();

  // Redirect ke login jika tidak authenticated
  if (!session) {
    return NextResponse.redirect(new URL('/login', req.url));
  }

  return res;
}

export const config = {
  matcher: ['/dashboard/:path*', '/profile/:path*']
};
BAGIAN 2

RLS Integration: auth.uid() Sekarang Berfungsi

-- Di Bab 8, auth.uid() return NULL
-- Sekarang, setelah user login, auth.uid() return user ID

CREATE POLICY "Users can view their own tasks"
ON tasks
FOR SELECT
USING (auth.uid() = user_id);  -- ✓ Sekarang bekerja!

CREATE POLICY "Users can insert their own tasks"
ON tasks
FOR INSERT
WITH CHECK (auth.uid() = user_id);

Moment ini adalah di mana security layer yang Anda bangun di Bab 8 "hidup." RLS policies yang tadinya dormant sekarang aktif dan enforce data isolation.

UPDATE APPLICATION CODE

Replace Hardcoded user_id

// ❌ Bab 8: Hardcoded
const { data } = await supabase
  .from('tasks')
  .insert({
    title: 'New task',
    user_id: '12345'  // BAD
  });
// ✅ Bab 9: Dynamic
const user = await supabase.auth.getUser();

const { data } = await supabase
  .from('tasks')
  .insert({
    title: 'New task',
    user_id: user.data.user.id
  });
  • Setiap task sekarang benar-benar milik user yang create
  • RLS policies enforce — user tidak bisa insert task dengan user_id orang lain
  • Query otomatis filtered berdasarkan authenticated user
ROLE-BASED ACCESS CONTROL

RBAC: Authorization Berdasarkan Roles

USER

Create, read, update own tasks. Tidak bisa lihat tasks orang lain.

ADMIN

Full access ke semua tasks. Bisa delete any task, manage users.

MODERATOR

Read all tasks, moderate content, tapi tidak bisa delete users.

Role stored di auth.users metadata atau separate user_roles table.

RBAC POLICIES

RLS Policies dengan Role Checks

-- Admin bisa lihat semua tasks
CREATE POLICY "Admins can view all tasks"
ON tasks
FOR SELECT
USING (
  (SELECT role FROM auth.users WHERE id = auth.uid()) = 'admin'
);

-- Regular user hanya lihat miliknya
CREATE POLICY "Users can view own tasks"
ON tasks
FOR SELECT
USING (
  auth.uid() = user_id OR
  (SELECT role FROM auth.users WHERE id = auth.uid()) = 'admin'
);
⚠️ Performance Note

Subquery di RLS bisa lambat. Consider denormalize role ke separate table dengan index.

BAGIAN 3

Password Security Best Practices

✅ DO
  • Hash passwords (bcrypt, argon2)
  • Enforce minimum length (12+ chars)
  • Require complexity (uppercase, lowercase, numbers, symbols)
  • Rate limit login attempts
  • Use HTTPS untuk transmit credentials
  • Expire sessions setelah inactivity
❌ DON'T
  • Store passwords in plaintext
  • Use weak hashing (MD5, SHA1)
  • Log passwords (even hashed)
  • Email passwords ke users
  • Allow common passwords (password123)
  • Skip rate limiting
SESSION MANAGEMENT

Secure Session Handling

localStorage vs Cookies
StorageSecurityUse Case
localStorage⚠️ Vulnerable to XSSSPAs, client-heavy
httpOnly Cookie✅ XSS-safeServer-rendered, high security
Session Expiration
  • Access token: short-lived (15 min)
  • Refresh token: long-lived (7 days)
  • Auto-refresh before expiration
  • Invalidate on logout

Supabase default: access token expires 1 hour, refresh token expires 30 days. Customizable via dashboard.

BAGIAN 4: WEB VULNERABILITIES

Cross-Site Scripting (XSS)

// ❌ VULNERABLE: User input langsung di-render
<div>{userInput}</div>

// User submit: <script>alert(document.cookie)</script>
// Result: Script dijalankan, cookie stolen!

// ✅ SAFE: React auto-escapes
<div>{userInput}</div>  // React mengubah < jadi &lt;

// ❌ BYPASS: dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userInput }} />  // NEVER DO THIS
Attack Vector

Attacker inject malicious script via input field, comment, atau URL parameter.

Prevention

Sanitize input, escape output, Content Security Policy (CSP) headers.

CSRF (CROSS-SITE REQUEST FORGERY)

Forged Requests dari Site Lain

// ❌ VULNERABLE: Accept any POST request
app.post('/api/delete-account', (req, res) => {
  deleteAccount(req.user.id);  // No CSRF protection
});

// Attacker site bisa trigger:
<form action="https://yourapp.com/api/delete-account" method="POST">
  <input type="submit" value="Click for prize!" />
</form>

// ✅ PROTECTED: Verify CSRF token
app.post('/api/delete-account', verifyCsrfToken, (req, res) => {
  deleteAccount(req.user.id);
});
  • CSRF token: random string generated per session, embedded di form
  • SameSite cookie attribute: prevent cookie sent di cross-site request
  • Verify Origin/Referer header
IDOR (INSECURE DIRECT OBJECT REFERENCE)

Accessing Resources Tanpa Authorization Check

// ❌ VULNERABLE: Tidak verify ownership
app.get('/api/tasks/:id', async (req, res) => {
  const task = await db.tasks.findById(req.params.id);
  res.json(task);  // Siapa saja bisa akses task ID manapun!
});

// ✅ PROTECTED: Verify user owns resource
app.get('/api/tasks/:id', async (req, res) => {
  const task = await db.tasks.findOne({
    id: req.params.id,
    user_id: req.user.id  // ✓ Check ownership
  });

  if (!task) return res.status(403).json({ error: 'Forbidden' });
  res.json(task);
});

RLS di Supabase automatically prevent IDOR — database enforce ownership check. Tapi tetap validate di application layer!

SQL INJECTION

Malicious SQL via User Input

// ❌ VULNERABLE: String concatenation
const query = `SELECT * FROM users WHERE email = '${userInput}'`;

// User input: ' OR '1'='1
// Result: SELECT * FROM users WHERE email = '' OR '1'='1'
// Returns ALL users!

// ✅ SAFE: Parameterized queries
const { data } = await supabase
  .from('users')
  .select('*')
  .eq('email', userInput);  // Supabase auto-escape
Attack Impact

Data leak, data manipulation, authentication bypass, bahkan DROP DATABASE.

Prevention

ALWAYS use parameterized queries atau ORM. NEVER concat user input into SQL.

BROKEN AUTHENTICATION

Common Auth Vulnerabilities

Weak Passwords

Allow "password123" atau tidak enforce complexity. Enforce min 12 chars + complexity.

No Rate Limiting

Unlimited login attempts → brute force possible. Limit 5 attempts/15 min.

Predictable Tokens

Sequential session IDs atau weak random. Use cryptographically secure random.

Session Fixation

Session ID tidak regenerate setelah login. Always regenerate.

Exposed Credentials

Hardcoded secrets di code atau commit ke git. Use env vars.

No Logout

Session tidak invalidated saat logout. Properly destroy session.

SECURITY PRINCIPLE

Defense in Depth

Frontend
Input Validation
Backend
Auth + Sanitize
Database
RLS + Constraints
Network
HTTPS + Firewall

Jangan rely pada single security layer. Stack multiple layers sehingga jika satu layer fail, layer lain masih protect.

  • Layer 1: Client validation untuk UX (cepat feedback)
  • Layer 2: Server validation untuk security (never trust client)
  • Layer 3: Database constraints untuk data integrity
  • Layer 4: Network security (HTTPS, rate limiting, firewall)
SECURITY HEADERS

HTTP Headers untuk Protection

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [
        { key: 'X-Frame-Options', value: 'DENY' },
        { key: 'X-Content-Type-Options', value: 'nosniff' },
        { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
        { key: 'Permissions-Policy', value: 'geolocation=(), microphone=()' },
        {
          key: 'Content-Security-Policy',
          value: "default-src 'self'; script-src 'self' 'unsafe-inline';"
        }
      ]
    }];
  }
};
CONTENT SECURITY POLICY

CSP: Mitigate XSS Attacks

CSP Directives
  • default-src 'self' — hanya load dari own domain
  • script-src 'self' — block inline scripts
  • style-src 'self' — block inline styles
  • img-src * — allow images dari anywhere
Trade-offs

CSP strict bisa break third-party scripts (Google Analytics, ads). Balance security vs functionality.

Start dengan CSP dalam report-only mode untuk detect violations tanpa block. Iteratively tighten policy.

HTTPS (TLS/SSL)

Encrypted Communication

HTTP: Plaintext

Data transmitted in clear text. Passwords, tokens, semua visible ke attacker di network.

HTTPS: Encrypted

TLS encryption. Man-in-the-middle attacker hanya lihat gibberish.

  • ALWAYS use HTTPS untuk production apps — terutama auth endpoints
  • Free SSL certificates via Let's Encrypt atau hosting providers
  • Redirect HTTP → HTTPS automatically
  • Enable HSTS (HTTP Strict Transport Security) header

Supabase auto-provides HTTPS endpoints. Next.js Vercel deployments auto-HTTPS. Localhost dev dapat exception (HTTP OK).

RATE LIMITING

Prevent Brute Force & DoS

// Supabase built-in rate limiting di auth endpoints
// Config via dashboard: Settings → API → Rate Limits

// Custom rate limiting dengan middleware
import rateLimit from 'express-rate-limit';

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 5,  // Max 5 attempts
  message: 'Too many login attempts. Try again later.'
});

app.post('/login', loginLimiter, handleLogin);
Login Endpoints

5 attempts / 15 min per IP

API Endpoints

100 requests / minute per user

Password Reset

3 requests / hour per email

BAGIAN 5: AI & SECURITY

AI Code Generation: Security Blind Spots

AI Sering Lupa
  • Input validation & sanitization
  • Authorization checks (IDOR)
  • Rate limiting implementation
  • CSRF token verification
  • Proper error messages (info leak)
  • Secure session config
AI Prioritas

AI optimize untuk "code yang bekerja," bukan "code yang aman." Security trade-offs tidak visible di AI training data.

⚠️ NEVER blindly copy-paste AI-generated auth/security code. ALWAYS review dengan Security Checklist.

SECURITY REVIEW CHECKLIST

Evaluasi AI-Generated Security Code

✓ Authentication
  • Password properly hashed?
  • Session tokens cryptographically secure?
  • Rate limiting on login?
  • Email verification implemented?
✓ Authorization
  • Every endpoint checks user permissions?
  • RLS policies active dan correct?
  • No IDOR vulnerabilities?
  • RBAC properly implemented?
✓ Input Validation
  • All user input sanitized?
  • SQL injection prevention?
  • XSS protection (escape output)?
  • File upload restrictions?
✓ Session & Transport
  • HTTPS enforced?
  • Secure cookie flags (httpOnly, Secure)?
  • CSRF protection enabled?
  • Session expiration configured?
SECURITY REVIEW FORMAT

Dokumentasi Review Security Code

## Security Review: Login API

### Authentication: ✅
- Password hashed dengan bcrypt (cost factor 12)
- Rate limiting: 5 attempts / 15 min per IP
- Session token: JWT dengan 1-hour expiration

### Input Validation: ⚠️
- Email format validated
- **MISSING:** Password strength check
- **RECOMMENDATION:** Enforce min 12 chars + complexity

### Transport Security: ✅
- HTTPS enforced via middleware
- httpOnly cookies untuk session storage

### Error Handling: ❌
- Error message: "Invalid email or password" ✓
- **ISSUE:** Server error leak stack trace ke client
- **FIX:** Sanitize error messages di production

### Keputusan: REQUEST CHANGES (fix error leak + password policy)
SECURITY TESTING

Test Security Scenarios

Manual Testing
  • Try access /dashboard tanpa login
  • Modify user_id di request → verify RLS block
  • Submit SQL injection payload di input
  • Try XSS: <script>alert(1)</script>
  • Test rate limiting dengan rapid requests
Automated Tools
  • OWASP ZAP — vulnerability scanner
  • Burp Suite — intercept & modify requests
  • npm audit — check dependency vulnerabilities
  • Snyk — continuous security monitoring

Think like an attacker. Try to break your own app. Better you find bugs than real attackers.

OWASP TOP 10 (2021)

Most Critical Web Security Risks

1. Broken Access Control

IDOR, privilege escalation, missing authorization.

2. Cryptographic Failures

Weak encryption, plaintext passwords, exposed secrets.

3. Injection

SQL, NoSQL, OS command, LDAP injection.

4. Insecure Design

Missing rate limiting, inadequate threat modeling.

5. Security Misconfiguration

Default credentials, verbose errors, missing headers.

6. Vulnerable Components

Outdated libraries dengan known vulnerabilities.

Full list: owasp.org/Top10

AUDIT LOGGING

Track Who Did What

// Audit log table
CREATE TABLE audit_logs (
  id BIGSERIAL PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id),
  action TEXT NOT NULL,  -- 'login', 'create_task', 'delete_user'
  resource_type TEXT,    -- 'task', 'user'
  resource_id BIGINT,
  ip_address INET,
  user_agent TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

// Log setiap sensitive action
async function logAction(userId, action, resourceType, resourceId) {
  await supabase.from('audit_logs').insert({
    user_id: userId,
    action: action,
    resource_type: resourceType,
    resource_id: resourceId,
    ip_address: req.ip,
    user_agent: req.headers['user-agent']
  });
}
INCIDENT RESPONSE

Ketika Security Breach Terjadi

1. Detect

Monitoring & alerts untuk unusual activity.

2. Contain

Isolate affected systems. Revoke compromised credentials.

3. Investigate

Analyze logs. Determine scope & root cause.

4. Remediate

Patch vulnerability. Update affected users.

5. Recover

Restore normal operations. Monitor untuk re-attack.

6. Learn

Post-mortem. Update security policies.

Have incident response plan BEFORE breach happens. Practice drills. Know who to contact.

SECRETS MANAGEMENT

Never Commit Secrets ke Git

❌ NEVER
// config.js
export const DB_PASSWORD = 'super_secret_123';
export const JWT_SECRET = 'my-jwt-key';

// .env file committed ke git
DATABASE_URL=postgres://user:pass@...
✅ ALWAYS
// .env.local (gitignored)
DATABASE_URL=postgres://...
JWT_SECRET=...

// .gitignore
.env.local
.env.*.local
  • Use environment variables untuk semua secrets
  • Different secrets untuk dev, staging, production
  • Rotate secrets regularly (quarterly atau post-breach)
  • Use secret management services (AWS Secrets Manager, HashiCorp Vault)
DEPENDENCY SECURITY

Third-Party Package Vulnerabilities

// Check vulnerabilities
npm audit

// Auto-fix jika available
npm audit fix

// View dependency tree
npm ls

// Keep dependencies updated
npm outdated
npm update
Supply Chain Attacks

Malicious code injected ke popular packages. Review package before install. Use lock files.

Automated Monitoring

Snyk, Dependabot, GitHub Security Alerts — auto-detect vulnerable dependencies dan create PRs.

CORS (CROSS-ORIGIN RESOURCE SHARING)

Control API Access dari Other Domains

// ❌ Too permissive
Access-Control-Allow-Origin: *  // Any domain bisa akses API

// ✅ Specific origins
Access-Control-Allow-Origin: https://yourapp.com

// Next.js API route
export default function handler(req, res) {
  res.setHeader('Access-Control-Allow-Origin', 'https://yourapp.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

  // Handle preflight
  if (req.method === 'OPTIONS') return res.status(200).end();

  // ... rest of handler
}
TWO-FACTOR AUTHENTICATION (2FA)

Extra Layer of Security

SMS OTP

6-digit code via text message. Simple tapi vulnerable ke SIM swapping.

TOTP Apps

Google Authenticator, Authy. Time-based codes. More secure.

Hardware Keys

YubiKey, USB security keys. Most secure, phishing-resistant.

2FA significantly reduce account takeover risk. Even if password leaked, attacker tetap butuh second factor.

Supabase support 2FA via phone verification. Implementasi di Bab 10 (Advanced Topics).

ENCRYPTION

Data at Rest vs In Transit

In Transit (HTTPS/TLS)

Protect data saat transmission dari browser ke server. Prevent man-in-the-middle attacks.

At Rest (DB Encryption)

Encrypt data di database. Jika server compromised, attacker tidak bisa read data.

  • Supabase: Database encryption at rest enabled by default (AES-256)
  • Passwords: Hashing (bcrypt) bukan encryption — one-way transform
  • PII/Sensitive: Consider column-level encryption untuk credit cards, SSN
  • Key Management: Rotate encryption keys regularly
PRE-DEPLOYMENT SECURITY CHECKLIST

Final Check Before Ship

Authentication & Authorization

  • ✓ Password hashing (bcrypt/argon2)
  • ✓ Rate limiting di login/signup
  • ✓ Email verification required
  • ✓ Session expiration configured
  • ✓ Protected routes via middleware
  • ✓ RLS policies active dan tested

Input & Output

  • ✓ Input validation (client + server)
  • ✓ SQL injection prevention
  • ✓ XSS protection (escape output)
  • ✓ CSRF token verification
  • ✓ File upload restrictions
  • ✓ Error messages sanitized

Transport & Headers

  • ✓ HTTPS enforced
  • ✓ Security headers configured
  • ✓ CSP enabled
  • ✓ CORS properly configured
  • ✓ httpOnly cookies

Operations

  • ✓ Secrets di env vars (not committed)
  • ✓ Dependencies updated (npm audit)
  • ✓ Audit logging implemented
  • ✓ Monitoring & alerts setup
  • ✓ Incident response plan documented
DEEP UNDERSTANDING ZONE

Pertanyaan Reflektif

  • Jelaskan perbedaan authentication vs authorization tanpa melihat notes. Berikan analogi konkret.
  • Mengapa storing password di plaintext sangat berbahaya? Apa yang bisa attacker lakukan dengan access ke database?
  • Draw diagram auth flow lengkap: dari user submit credentials sampai authenticated request ke API.
  • Mengapa localStorage vulnerable ke XSS? Apa alternative yang lebih aman?
  • Jelaskan bagaimana RLS policies di Bab 8 "hidup" setelah implement auth di Bab 9.
  • Defense in depth: explain mengapa multiple security layers lebih baik dari single strong layer.
  • Jika user report "Saya bisa lihat task orang lain," apa first debugging steps Anda?
VIBE CODING

Eksplorasi & Ekstensi Security

OAuth Integration

Add "Login with Google" atau GitHub via Supabase Auth providers.

Magic Links

Passwordless login via email link (seperti Notion, Slack).

2FA Implementation

Add SMS atau TOTP second factor dengan Supabase phone auth.

Admin Dashboard

Build admin panel dengan RBAC. View all users, manage permissions.

Security Audit Log Viewer

UI untuk view audit logs. Filter by user, action, date range.

Penetration Testing

Run OWASP ZAP scan terhadap app. Document findings dan fixes.

KONEKSI

Ke Bab Selanjutnya

Menuju Bab 10

Deployment & Production — HTTPS setup, environment variables, CI/CD, monitoring, dan production security hardening.

Advanced Topics

Multi-tenancy, API rate limiting tiers, advanced RBAC, compliance (GDPR, SOC2).

  • Security bukan one-time task — continuous process
  • Stay updated dengan security advisories (CVEs, OWASP)
  • Defense in depth: layer security di setiap level stack
  • Trust nothing, verify everything (Zero Trust principle)
REFLEKSI

Dari Prototype ke Production-Ready

"Aplikasi yang 'bekerja' belum tentu siap production. Security lapisan demi lapisan adalah yang membedakan demo dari aplikasi nyata."

  • Bab 8: Data persistent, tapi semua orang punya full access
  • Bab 9: Real users, authentication, authorization, dan data isolation
  • Mindset shift: Dari "buat fitur" ke "buat fitur yang aman"
  • AI awareness: AI generate code yang bekerja, tapi security adalah tanggung jawab Anda

Anda sekarang memiliki security-first mindset. Aplikasi Anda bukan hanya functional — it's secure.

BAB 9 COMPLETE

SECURITY IS
NOT A FEATURE.
IT'S A REQUIREMENT.

Authentication ✓

Real users, sessions, JWT tokens

Authorization ✓

RLS, RBAC, data isolation

Security ✓

Defense in depth, vulnerability prevention

Next: Deploy aplikasi production-ready Anda ke web di Bab 10.