JavaScript memungkinkan interaktivitas dinamis di website, tetapi rentan terhadap serangan keamanan seperti Cross-Site Scripting (XSS) dan Cross-Site Request Forgery (CSRF). Kesalahan keamanan ini bisa menyebabkan:
- Pencurian data pengguna
- Manipulasi konten website
- Kerugian bisnis dan reputasi
Artikel ini membahas secara mendalam XSS, CSRF, contoh nyata serangan, dan strategi pencegahan efektif.
Contents
1. Cross-Site Scripting (XSS)
1.1 Apa itu XSS
XSS terjadi ketika attacker menyisipkan script jahat ke website yang dijalankan di browser pengguna.
Tipe XSS:
- Reflected XSS – script terkirim melalui URL atau input form, dieksekusi seketika.
- Stored XSS – script tersimpan di server (misal database) → dieksekusi setiap ada user mengakses halaman.
- DOM-based XSS – script dieksekusi sepenuhnya di browser, manipulasi DOM.
1.2 Contoh Reflected XSS
Scenario: search query di website tidak disanitasi.
// search.js
const params = new URLSearchParams(window.location.search);
document.getElementById('results').innerHTML = params.get('q');
Serangan:
https://example.com/search?q=<script>alert('XSS')</script>
Akibat:
- Browser mengeksekusi
alert('XSS') - Bisa diganti script berbahaya untuk mencuri cookie atau token
1.3 Contoh Stored XSS
Scenario: komentar user tidak disanitasi.
// server.js
app.post('/comment', (req, res) => {
db.save(req.body.comment); // tidak sanitize
});
Serangan:
- User menyisipkan
<script>document.cookie</script>→ setiap orang yang melihat komentar akan mengeksekusi script → cookie dicuri
1.4 Contoh DOM-based XSS
// script.js
const hash = window.location.hash;
document.getElementById('content').innerHTML = hash.substring(1);
Serangan:
https://example.com/#<img src=x onerror=alert(1)>
- Script dieksekusi di browser sepenuhnya tanpa melewati server
1.5 Pencegahan XSS
- Sanitize input user
- Gunakan library: DOMPurify, xss-filters
const clean = DOMPurify.sanitize(userInput); document.getElementById('results').innerHTML = clean; - Escape output
- Jangan langsung gunakan
innerHTML, gunakantextContentjika bisa
- Jangan langsung gunakan
- Content Security Policy (CSP)
- Batasi sumber script yang diperbolehkan
Content-Security-Policy: default-src 'self'; script-src 'self' - Hindari eval / new Function
- Jangan mengeksekusi JS dari input user
- Validate & encode input di server
- Selalu lakukan sanitasi di backend sebelum menyimpan ke database
2. Cross-Site Request Forgery (CSRF)
2.1 Apa itu CSRF
CSRF terjadi ketika attacker memaksa user melakukan request ke server yang sah menggunakan sesi atau cookie yang masih aktif.
Contoh nyata:
- User login di bank.com → attacker membuat
<img src="https://bank.com/transfer?amount=1000&to=attacker"> - Browser otomatis mengirim request dengan cookie → transfer uang terjadi
2.2 Pencegahan CSRF
- CSRF Token
- Setiap form atau request memiliki token unik.
<form method="POST" action="/transfer">
<input type="hidden" name="csrf_token" value="UNIQUE_TOKEN_HERE">
<input type="submit" value="Transfer">
</form>
- Server validasi token sebelum memproses request
- SameSite Cookies
- Batasi cookie agar hanya dikirim ke request dari domain yang sama
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure
- Custom Headers / Double Submit Cookie
- AJAX request wajib menyertakan header khusus → server cek kesesuaian
- Validasi HTTP Referer / Origin
- Pastikan request berasal dari domain yang sah
3. Contoh Nyata Implementasi XSS + CSRF Protection
// Express + CSRF Middleware
const express = require('express');
const csurf = require('csurf');
const bodyParser = require('body-parser');
const DOMPurify = require('dompurify');
const app = express();
const csrfProtection = csurf({ cookie: true });
app.use(bodyParser.urlencoded({ extended: false }));
app.use(require('cookie-parser')());
// Form route
app.get('/comment', csrfProtection, (req, res) => {
res.send(`
<form method="POST">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<textarea name="comment"></textarea>
<button type="submit">Submit</button>
</form>
`);
});
// Process comment
app.post('/comment', csrfProtection, (req, res) => {
const sanitizedComment = DOMPurify.sanitize(req.body.comment);
db.save(sanitizedComment);
res.send('Comment saved safely!');
});
Keunggulan:
- XSS dicegah dengan
DOMPurify.sanitize - CSRF dicegah dengan token unik di setiap form
4. Best Practice JavaScript Security Production
- Selalu sanitize input & escape output
- Gunakan HTTPS untuk semua request → lindungi cookie dan token
- Content Security Policy (CSP) → batasi script dari sumber luar
- Gunakan CSRF Token atau SameSite cookies
- Hindari eval / innerHTML langsung dari input user
- Audit third-party scripts → library eksternal bisa menjadi vektor XSS
- Gunakan security headers tambahan:
X-Content-Type-Options: nosniffX-Frame-Options: DENYStrict-Transport-Security: max-age=31536000; includeSubDomains
5. Studi Kasus Nyata
5.1 E-Commerce Comment Section (Stored XSS)
- Masalah: komentar user tidak disanitasi → attacker sisipkan
<script>document.cookie</script> - Dampak: setiap visitor website → cookie dicuri → session hijacking
- Solusi: sanitize input dengan DOMPurify + CSP
- Hasil: XSS dicegah, website aman, SEO & UX stabil
5.2 Banking Transfer Form (CSRF)
- Masalah: attacker buat form fake → user login → transfer otomatis
- Solusi: implement CSRF token + SameSite cookie
- Hasil: setiap request diverifikasi → serangan CSRF gagal
6. Checklist JavaScript Security
- Sanitize & escape semua input user
- Gunakan
textContentdaripadainnerHTMLbila memungkinkan - Implement CSP → batasi sumber script
- Gunakan CSRF Token / SameSite cookie untuk request sensitif
- Audit semua library pihak ketiga
- Hindari eval / dynamic JS dari input user
- Gunakan HTTPS & security headers
7. Kesimpulan
XSS dan CSRF adalah dua vektor serangan utama JavaScript yang dapat merusak website dan mencuri data pengguna.
Dengan:
- Sanitasi input
- Escape output
- CSP
- CSRF token / SameSite cookie
- HTTPS & security headers
…website menjadi aman, SEO-friendly, dan stabil untuk user.
Implementasi praktis & production-ready seperti contoh Express + DOMPurify + CSRF Token akan melindungi aplikasi dari serangan umum, sambil tetap menjaga UX dan performa.