Lewati ke konten

Security Guide

Security Guide

Panduan Instalasi

INA Digital Design System adalah pustaka komponen UI berbasis React dan Vue yang siap di-publish ke NPM dan di-consume oleh berbagai proyek.

INA Digital Design System telah mengimplementasikan berbagai fitur keamanan untuk melindungi aplikasi dari serangan umum seperti Cross-Site Scripting (XSS) dan file upload vulnerabilities. Panduan ini menjelaskan fitur-fitur keamanan yang tersedia dan cara menggunakannya dengan benar.

Penting

Validasi server-side tetap wajib dilakukan! Fitur keamanan di design system ini adalah defense-in-depth dan UX enhancement, bukan pengganti validasi server-side. Selalu validasi dan sanitize data di server sebelum menyimpan ke database.

Design system ini mengikuti prinsip-prinsip keamanan berikut:

  1. Defense-in-Depth: Multiple layers of security
  2. Whitelist Approach: Allowlist, bukan blacklist
  3. Safe Defaults: Default configuration yang aman
  4. OWASP Compliance: Mengikuti rekomendasi OWASP

Komponen TextField dan TextArea memiliki built-in XSS protection yang dapat diaktifkan melalui prop securityConfig.

import { TextField } from '@idds/react';
import { DEFAULT_SECURITY_CONFIG } from '@idds/react';
function MyForm() {
const [value, setValue] = useState('');
return (
<TextField
value={value}
onChange={setValue}
securityConfig={{
enableXssProtection: true, // Default: true
logViolations: true,
onSecurityViolation: (threats, input) => {
console.warn('Security threat detected:', threats);
// Kirim ke monitoring service
},
}}
/>
);
}
<template>
<TextField
v-model="value"
:security-config="{
enableXssProtection: true,
logViolations: true,
onSecurityViolation: handleSecurityViolation,
}"
/>
</template>
<script setup lang="ts">
import { TextField } from '@idds/vue';
import type { SecurityConfig } from '@idds/vue';
const value = ref('');
const handleSecurityViolation = (threats: string[], input: string) => {
console.warn('Security threat detected:', threats);
// Kirim ke monitoring service
};
</script>

Gunakan privacy props untuk melindungi data sensitif dari browser suggestions dan telemetry:

// Field sensitif (OTP, token, password)
<TextField
autocomplete="off"
spellCheck={false}
autoCapitalize="off"
autoCorrect="off"
/>
// Email field
<TextField
type="email"
inputMode="email"
autoCapitalize="none"
autoCorrect="off"
/>
// Nomor telepon
<TextField
type="tel"
inputMode="tel"
autoCapitalize="off"
/>

Gunakan prop validation untuk validasi terstruktur:

<TextField
value={nip}
onChange={setNip}
validation={[
{
kind: 'regex',
pattern: /^\d{18}$/,
message: 'NIP harus 18 digit',
},
{
kind: 'minLength',
value: 18,
message: 'NIP minimal 18 karakter',
},
]}
/>

Gunakan prop normalize untuk normalisasi value (misalnya menghapus spasi):

<TextField
value={phoneNumber}
onChange={setPhoneNumber}
normalize={(v) => v.replace(/\s+/g, '')} // Hapus semua spasi
/>

Default: true - Sesuai rekomendasi OWASP, magic number validation diaktifkan secara default untuk memverifikasi file signature.

<FileUpload
type="image/png,image/jpeg"
allowedExtensions={['png', 'jpg', 'jpeg']}
maxSize={5 * 1024 * 1024} // 5MB
validateMagicNumber={true} // Default: true
maxFiles={10}
maxTotalSizeMB={50}
onChange={(files, errors) => {
// Handle files
}}
/>

Selalu gunakan allowedExtensions untuk membatasi ekstensi file yang diizinkan:

<FileUpload allowedExtensions={['png', 'jpg', 'pdf']} type="image/*,application/pdf" />

Batasi jumlah dan ukuran total file untuk mencegah abuse:

<FileUpload
multiple={true}
maxFiles={10} // Maksimal 10 file
maxTotalSizeMB={100} // Total maksimal 100MB
maxSize={10 * 1024 * 1024} // Per file maksimal 10MB
/>
// ❌ JANGAN: Hanya mengandalkan validasi frontend
const handleSubmit = async (data) => {
await api.post('/submit', data);
};
// ✅ BENAR: Validasi di server juga
const handleSubmit = async (data) => {
// Frontend validation (UX)
if (!validateNIP(data.nip)) {
setError('NIP tidak valid');
return;
}
// Server validation (Security)
const response = await api.post('/submit', data);
if (!response.data.isValid) {
setError(response.data.error);
}
};

Selalu sanitize data sebelum menampilkan kembali ke user:

// ❌ JANGAN: Render langsung tanpa sanitize
<div>{userInput}</div>
// ✅ BENAR: Sanitize atau gunakan text node
<div>{sanitizeHtml(userInput)}</div>
// atau
<div>{userInput}</div> // React/Vue sudah auto-escape

Selalu gunakan HTTPS untuk mengamankan komunikasi:

// ✅ Pastikan API endpoint menggunakan HTTPS
const API_URL = 'https://api.example.com';

Implementasikan CSP di aplikasi Anda:

<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
/>
  • ✅ Validasi MIME type di server
  • ✅ Validasi magic number di server
  • ✅ Rename file dengan UUID/nama aman
  • ✅ Simpan file di lokasi yang tidak dapat diakses langsung
  • ✅ Scan malware untuk file yang diupload
  • ✅ Batasi ukuran file
  • ✅ Batasi jumlah file
  • ✅ Gunakan allowlist extension
import { DEFAULT_SECURITY_CONFIG } from '@idds/react';
// Default configuration:
{
enableXssProtection: true,
maxLength: 10000,
allowHtml: false,
stripScripts: true,
stripEvents: true,
logViolations: true,
onSecurityViolation: (threats, input) => {
// Log di development
if (window.location.hostname === 'localhost') {
console.warn('Security violation:', threats);
}
},
}
<TextField
securityConfig={{
enableXssProtection: true,
maxLength: 5000,
logViolations: true,
onSecurityViolation: (threats, input) => {
// Kirim ke monitoring service
analytics.track('security_violation', {
threats,
inputLength: input.length,
timestamp: Date.now(),
});
},
}}
/>

Threat: User memasukkan script berbahaya yang dieksekusi di browser.

Protection:

  • ✅ XSS protection di TextField/TextArea (default: enabled)
  • ✅ Auto-sanitization
  • ✅ React/Vue auto-escape

Example:

// Input berbahaya: <script>alert('XSS')</script>
// Output aman: &lt;script&gt;alert('XSS')&lt;/script&gt;

Threat: User upload file berbahaya (executable, malware, dll).

Protection:

  • ✅ Magic number validation (default: enabled)
  • ✅ Extension allowlist
  • ✅ MIME type validation
  • ✅ File size limits

Example:

// File: malicious.exe (renamed to image.png)
// ❌ Ditolak: Magic number tidak sesuai dengan MIME type

Threat: User mencoba mengakses file di luar direktori yang diizinkan.

Protection:

  • ✅ Sanitized file name display
  • ✅ Server-side: Rename file dengan UUID

Example:

// Input: ../../../etc/passwd
// Output: sanitized filename
<TextField
securityConfig={{
logViolations: true,
onSecurityViolation: (threats, input) => {
// Kirim ke monitoring service
sendToMonitoring({
type: 'xss_attempt',
threats,
input: input.substring(0, 100), // Jangan log full input
user: getCurrentUser(),
timestamp: Date.now(),
});
},
}}
/>

Jika Anda menemukan vulnerability atau memiliki pertanyaan tentang keamanan, silakan hubungi tim security di security@example.com.