Hugo Security Best Practices: Mengamankan Website Hugo
Hugo Security Best Practices: Mengamankan Website Hugo
Meskipun Hugo sites secara inheren lebih aman karena sifatnya yang static, tetap ada aspek security yang perlu diperhatikan untuk memastikan website Anda terlindungi dari berbagai threats. Dalam panduan ini, kita akan membahas best practices untuk mengamankan website Hugo, mulai dari server configuration hingga content security.
Static sites memiliki attack surface yang lebih kecil dibandingkan dynamic sites karena tidak ada database atau server-side processing yang bisa dieksploitasi. Namun, ini tidak berarti website static sepenuhnya immune dari security issues. Ada beberapa area yang perlu perhatian khusus untuk memastikan security yang comprehensive.
Server Security
Firewall Configuration
# Install and configure UFW
sudo apt install ufw
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH
sudo ufw allow ssh
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable UFW
sudo ufw enable
# Check status
sudo ufw status verbose
SSH Hardening
# /etc/ssh/sshd_config
# Disable root login
PermitRootLogin no
# Disable password authentication
PasswordAuthentication no
# Use only protocol 2
Protocol 2
# Limit login attempts
MaxAuthTries 3
MaxSessions 5
# Idle timeout
ClientAliveInterval 300
ClientAliveCountMax 2
# Banner
Banner /etc/ssh/banner
# Generate SSH key
ssh-keygen -t ed25519 -C "your-email@example.com"
# Copy public key to server
ssh-copy-id user@server-ip
# Restart SSH
sudo systemctl restart sshd
Fail2ban Configuration
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
[nginx-noscript]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 6
bantime = 86400
Web Server Security
Nginx Security Headers
# /etc/nginx/conf.d/security-headers.conf
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:;" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Rate Limiting
# /etc/nginx/conf.d/rate-limit.conf
# Rate limit zones
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
# Apply rate limiting
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
}
location /login {
limit_req zone=login burst=5 nodelay;
}
location / {
limit_conn conn 10;
}
}
Disable Unnecessary Features
# Disable server version in headers
server_tokens off;
# Disable directory listing
autoindex off;
# Disable .htaccess (for Apache compatibility)
location ~ /\.ht {
deny all;
}
SSL/TLS Configuration
Let’s Encrypt Setup
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com
# Verify auto-renewal
sudo certbot renew --dry-run
# Enable auto-renewal
sudo systemctl enable certbot.timer
SSL Configuration
# /etc/nginx/snippets/ssl-params.conf
# SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Diffie-Hellman
ssl_dhparam /etc/nginx/dhparam.pem;
# Generate DH parameters
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
File System Security
Proper Permissions
#!/bin/bash
# scripts/set-permissions.sh
WEB_ROOT="/var/www/example.com"
USER="www-data"
GROUP="www-data"
# Set owner
sudo chown -R ${USER}:${GROUP} ${WEB_ROOT}
# Set directory permissions
sudo find ${WEB_ROOT} -type d -exec chmod 755 {} \;
# Set file permissions
sudo find ${WEB_ROOT} -type f -exec chmod 644 {} \;
# Secure sensitive files
sudo chmod 600 /etc/nginx/conf.d/
sudo chmod 600 /etc/letsencrypt/
# Log files should be writable but not readable by all
sudo chmod 640 /var/log/nginx/
Protect Sensitive Files
# Protect .git, .env, and other sensitive files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~ /\.env {
deny all;
}
location ~ /\.git {
deny all;
}
Content Security Policy
CSP Implementation
# Strict CSP
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://www.google-analytics.com;
frame-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'self';
" always;
CSP Report-Only
# For testing CSP
add_header Content-Security-Policy-Report-Only "
default-src 'self';
report-uri /csp-report;
report-to csp-endpoint;
" always;
API Security
API Gateway Configuration
# API rate limiting dan authentication
location /api/ {
# Rate limiting
limit_req zone=api burst=20 nodelay;
# JWT verification (with nginx-jwt module)
jwt_issuer "your-issuer";
jwt_signature_key file:/etc/nginx/jwt.key;
# Validate claims
jwt_claim_exp 3600;
# Forward to backend
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Input Validation
Untuk API endpoints, selalu validasi input:
// Example: Validate API input
function validateInput(body) {
const schema = {
name: { type: 'string', maxLength: 100 },
email: { type: 'string', pattern: /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/ },
age: { type: 'number', min: 0, max: 150 }
};
for (const [key, rules] of Object.entries(schema)) {
if (body[key] === undefined && !rules.optional) {
throw new Error(`Missing required field: ${key}`);
}
if (body[key] !== undefined) {
if (typeof body[key] !== rules.type) {
throw new Error(`Invalid type for ${key}`);
}
if (rules.pattern && !rules.pattern.test(body[key])) {
throw new Error(`Invalid format for ${key}`);
}
if (rules.maxLength && body[key].length > rules.maxLength) {
throw new Error(`${key} too long`);
}
}
}
return true;
}
Monitoring dan Alerting
Log Configuration
# /etc/nginx/conf.d/logging.conf
# Custom log format with more details
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log detailed;
error_log /var/log/nginx/error.log warn;
Security Monitoring Script
#!/bin/bash
# scripts/security-monitor.sh
LOG_FILE="/var/log/nginx/access.log"
REPORT_FILE="/tmp/security-report-$(date +%Y%m%d).txt"
# Failed login attempts
echo "=== Failed Login Attempts ===" > ${REPORT_FILE}
grep "POST /login" ${LOG_FILE} | \
awk '{print $1}' | sort | uniq -c | sort -rn | \
awk '$1 > 5 {print}' >> ${REPORT_FILE}
# 404 scans
echo -e "\n=== Potential 404 Scans ===" >> ${REPORT_FILE}
awk '$9 == 404 {print $7}' ${LOG_FILE} | \
sort | uniq -c | sort -rn | \
awk '$1 > 10 {print}' >> ${REPORT_FILE}
# SQL Injection attempts
echo -e "\n=== Potential SQL Injection ===" >> ${REPORT_FILE}
grep -E "(union|select|insert|update|delete|drop|alter)" ${LOG_FILE} | \
awk '{print $1, $7}' | sort | uniq -c | sort -rn | \
head -20 >> ${REPORT_FILE}
# XSS attempts
echo -e "\n=== Potential XSS Attempts ===" >> ${REPORT_FILE}
grep -E "(<script|javascript:|onerror|onload|alert\()" ${LOG_FILE} | \
awk '{print $1, $7}' | sort | uniq -c | sort -rn | \
head -20 >> ${REPORT_FILE}
# Send report
mail -s "Daily Security Report" admin@example.com < ${REPORT_FILE}
GitHub Actions Security
Secret Management
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy
run: |
# Use secrets from GitHub
echo "${{ secrets.SSH_PRIVATE_KEY }}" > deploy_key
chmod 600 deploy_key
scp -i deploy_key files user@server:/path/
env:
# Secrets available as environment variables
API_TOKEN: ${{ secrets.API_TOKEN }}
Dependency Scanning
# .github/workflows/security-scan.yml
name: Security Scan
on:
push:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
Regular Security Audits
Automated Audit Script
#!/bin/bash
# scripts/security-audit.sh
echo "=== Hugo Site Security Audit ==="
echo "Date: $(date)"
echo ""
# Check SSL certificate
echo "=== SSL Certificate ==="
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Check security headers
echo -e "\n=== Security Headers ==="
curl -I https://example.com 2>/dev/null | grep -i "strict-transport\|x-frame\|x-content-type\|x-xss\|content-security"
# Check for outdated dependencies
echo -e "\n=== Dependencies ==="
if [ -f "package.json" ]; then
npm audit --audit-level=high
fi
# Check file permissions
echo -e "\n=== File Permissions ==="
find . -name "*.env" -exec ls -la {} \; 2>/dev/null
echo -e "\n=== Audit Complete ==="
Best Practices Summary
| Area | Practice |
|---|---|
| Server | Firewall, SSH hardening, Fail2ban |
| Web Server | Security headers, Rate limiting, SSL/TLS |
| Filesystem | Proper permissions, Protect sensitive files |
| CSP | Strict policy, Report-only mode for testing |
| Monitoring | Log analysis, Alerting, Regular audits |
| CI/CD | Secret management, Dependency scanning |
Kesimpulan
Meskipun Hugo sites secara inheren lebih aman, security yang comprehensive tetap essential. Dengan mengimplementasikan best practices yang dibahas dalam panduan ini, website Hugo Anda akan memiliki security posture yang kuat terhadap berbagai threats.
Artikel Terkait
Link Postingan : https://www.tirinfo.com/security-best-practices-hugo/