Workshop: Linux Server Hardening — เพิ่มความปลอดภัยทุกด้าน

Linux Server Hardening คือกระบวนการเพิ่มความปลอดภัยให้ Server โดยลด Attack Surface ให้เหลือน้อยที่สุด ปิดบริการที่ไม่จำเป็น ตั้งค่า Permission ให้ถูกต้อง และเพิ่มชั้นการป้องกันหลายระดับ เพื่อให้ Server ทนต่อการโจมตีได้ดีขึ้น Workshop นี้รวบรวม Hardening Checklist ที่ครอบคลุมทุกด้านสำหรับ Production Server

บทความนี้ต่อเนื่องจาก Workshop: Complete VPS Server Setup โดยเน้นเฉพาะด้านความปลอดภัย ครอบคลุม User/Permission Hardening, Network Hardening, Service Hardening, Kernel Security, Audit Logging และการ Monitor ความผิดปกติ

1. User และ Permission Hardening

# ตรวจสอบ User ที่มี UID 0 (root-equivalent)
awk -F: '($3 == 0) {print}' /etc/passwd

# ล็อค Account ที่ไม่ได้ใช้
passwd -l username      # Lock
passwd -u username      # Unlock (ถ้าต้องการ)

# ตรวจสอบ User ที่ไม่มี Password
awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow

# ตั้งค่า Password Policy (Ubuntu)
apt install -y libpam-pwquality
# แก้ไข /etc/security/pwquality.conf:
# minlen = 12
# dcredit = -1    # ต้องมีตัวเลขอย่างน้อย 1
# ucredit = -1    # ต้องมีตัวพิมพ์ใหญ่อย่างน้อย 1
# lcredit = -1    # ต้องมีตัวพิมพ์เล็กอย่างน้อย 1
# ocredit = -1    # ต้องมีอักขระพิเศษอย่างน้อย 1
# ตั้งค่า Password Aging
chage -M 90 -m 1 -W 7 username    # Max 90 วัน, Min 1 วัน, Warning 7 วัน
chage -l username                  # ดูค่าปัจจุบัน

# แก้ไข /etc/login.defs สำหรับ Policy ทั่วไป
# PASS_MAX_DAYS   90
# PASS_MIN_DAYS   1
# PASS_WARN_AGE   7
# LOGIN_RETRIES   3
# LOGIN_TIMEOUT   60

# ล็อก Session Timeout (ใส่ใน /etc/profile.d/timeout.sh)
echo 'TMOUT=900' > /etc/profile.d/timeout.sh
echo 'readonly TMOUT' >> /etc/profile.d/timeout.sh
echo 'export TMOUT' >> /etc/profile.d/timeout.sh
# ตรวจสอบ SUID/SGID Files ที่ผิดปกติ
find / -perm -4000 -type f 2>/dev/null | sort   # SUID
find / -perm -2000 -type f 2>/dev/null | sort   # SGID

# ตรวจสอบ World-writable Files
find / -perm -0002 -type f 2>/dev/null | grep -v proc | grep -v sys

# ตรวจสอบ Files ที่ไม่มี Owner
find / -nouser -o -nogroup 2>/dev/null | grep -v proc

2. SSH Hardening

# /etc/ssh/sshd_config — ค่า Hardening สมบูรณ์
cat > /etc/ssh/sshd_config.d/99-hardening.conf <<'EOF'
# Port และ Protocol
Port 2222
Protocol 2

# Authentication
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
LoginGraceTime 30

# Session
ClientAliveInterval 300
ClientAliveCountMax 2
MaxSessions 4
MaxStartups 10:30:60

# Disable Unused Features
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitEmptyPasswords no
PermitUserEnvironment no

# Logging
LogLevel VERBOSE

# Crypto (Strong ciphers only)
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
EOF

sshd -t && systemctl restart sshd

3. Kernel Hardening (sysctl)

cat > /etc/sysctl.d/99-hardening.conf <<'EOF'
# ปิด IP Forwarding (ถ้าไม่ใช้เป็น Router)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# ป้องกัน Spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# ปิด ICMP Redirect
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# ป้องกัน SYN Flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5

# ปิด Source Routing
net.ipv4.conf.all.accept_source_route = 0

# ป้องกัน Smurf Attack
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Memory Protection
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2

# ปิด Magic SysRq
kernel.sysrq = 0

# Restrict ptrace
kernel.yama.ptrace_scope = 1
EOF

sysctl -p /etc/sysctl.d/99-hardening.conf

4. Filesystem Hardening

# /etc/fstab — เพิ่ม Mount Options ที่ปลอดภัย
# ตัวอย่างสำหรับ /tmp:
# tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0

# ตรวจสอบ Mount Options ปัจจุบัน
mount | grep " / \| /tmp \| /var \| /home "

# สร้าง /tmp ที่ปลอดภัย (ถ้ายังไม่ได้ทำ)
systemctl enable tmp.mount
# หรือแก้ /etc/fstab:
# tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec,size=512M 0 0

# ตั้งค่า Sticky Bit บน /tmp และ /var/tmp
chmod 1777 /tmp
chmod 1777 /var/tmp
# ตั้งค่า umask ที่เข้มงวดขึ้น (Default 022 → 027)
# /etc/profile หรือ /etc/bash.bashrc
echo "umask 027" >> /etc/profile.d/hardening.sh

# ปกป้องไฟล์ Config สำคัญ
chmod 600 /etc/passwd-
chmod 600 /etc/shadow
chmod 600 /etc/gshadow
chmod 644 /etc/passwd
chmod 644 /etc/group

# ล็อค /etc/passwd ไม่ให้แก้ไขโดยไม่ตั้งใจ
chattr +i /etc/passwd  # ระวัง: ต้อง chattr -i ก่อนแก้ไข

5. Network Service Hardening

# ตรวจสอบ Port ที่เปิดอยู่
ss -tlnp
netstat -tlnp

# ปิด Service ที่ไม่จำเป็น
systemctl list-unit-files --type=service --state=enabled

# ตัวอย่าง Service ที่มักไม่จำเป็นบน Production Server
for svc in avahi-daemon cups bluetooth; do
  if systemctl is-enabled "$svc" 2>/dev/null | grep -q enabled; then
    systemctl disable --now "$svc"
    echo "Disabled: $svc"
  fi
done

# ตรวจสอบ Process ที่ฟัง Network
lsof -i -P -n | grep LISTEN
# Nginx Security Headers
cat > /etc/nginx/conf.d/security-headers.conf <<'EOF'
# ซ่อน Nginx Version
server_tokens off;

# 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'; style-src 'self' 'unsafe-inline';" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
EOF

nginx -t && systemctl reload nginx

6. Audit Logging ด้วย auditd

# ติดตั้ง auditd
apt install -y auditd audispd-plugins
systemctl enable --now auditd

# เพิ่ม Audit Rules
cat > /etc/audit/rules.d/99-hardening.rules <<'EOF'
# ลบ Rule เดิม
-D

# Buffer Size
-b 8192

# ติดตาม Authentication
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers

# ติดตาม Login Events
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock/ -p wa -k logins

# ติดตาม sudo Usage
-w /usr/bin/sudo -p x -k sudo_usage

# ติดตาม SSH Config
-w /etc/ssh/sshd_config -p wa -k sshd

# ติดตาม Network Config
-w /etc/hosts -p wa -k network
-w /etc/network/ -p wa -k network

# ติดตาม Cron
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron

# ติดตาม Privileged Commands
-a always,exit -F path=/usr/bin/passwd -F perm=x -k privileged
-a always,exit -F path=/usr/bin/su -F perm=x -k privileged
-a always,exit -F path=/usr/bin/sudo -F perm=x -k privileged
EOF

augenrules --load
auditctl -l | head -20
# ดู Audit Log
ausearch -k sudo_usage -i | tail -20
ausearch -k identity -i | tail -20

# สร้าง Audit Report
aureport --auth --summary   # Login Summary
aureport --failed            # Failed Events
aureport --executable        # Executable Summary

7. AppArmor / SELinux

# Ubuntu — AppArmor
systemctl status apparmor
aa-status | grep -E "profiles|processes"

# บังคับใช้ Profile ที่อยู่ใน Complain Mode
aa-enforce /etc/apparmor.d/usr.sbin.nginx
aa-enforce /etc/apparmor.d/usr.sbin.mysqld

# ตรวจสอบ AppArmor Violations
grep "apparmor" /var/log/syslog | grep DENIED | tail -20

# RHEL/Rocky — SELinux
sestatus
getenforce   # Enforcing/Permissive/Disabled

# บังคับใช้ Enforcing Mode
setenforce 1
# ถาวร: แก้ SELINUX=enforcing ใน /etc/selinux/config

8. Log Monitoring และ Alerting

cat > /usr/local/bin/security-monitor.sh <<'EOF'
#!/bin/bash
LOG="/var/log/security-monitor.log"
ALERT_EMAIL="[email protected]"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

log() { echo "[$DATE] $1" >> "$LOG"; }

FAILED=$(grep "Failed password" /var/log/auth.log 2>/dev/null | grep "$(date '+%b %e')" | wc -l)
if [ "$FAILED" -gt 20 ]; then
  log "ALERT: $FAILED failed logins today"
  echo "$FAILED failed logins on $(hostname)" | mail -s "[Security Alert] Failed Logins" "$ALERT_EMAIL"
fi

ROOT_LOGINS=$(grep "session opened for user root" /var/log/auth.log 2>/dev/null | grep "$(date '+%b %e')" | wc -l)
if [ "$ROOT_LOGINS" -gt 0 ]; then
  log "WARNING: $ROOT_LOGINS root login(s) today"
fi

SUID_CACHE="/var/cache/suid-files.txt"
CURRENT_SUID=$(find / -perm -4000 -type f 2>/dev/null | sort)
if [ -f "$SUID_CACHE" ]; then
  NEW_SUID=$(diff "$SUID_CACHE" <(echo "$CURRENT_SUID") | grep "^>" | sed 's/^> //')
  if [ -n "$NEW_SUID" ]; then
    log "ALERT: New SUID files found: $NEW_SUID"
    echo "New SUID files on $(hostname): $NEW_SUID" | mail -s "[Security Alert] New SUID" "$ALERT_EMAIL"
  fi
fi
echo "$CURRENT_SUID" > "$SUID_CACHE"

PORTS_CACHE="/var/cache/listening-ports.txt"
CURRENT_PORTS=$(ss -tlnp | grep LISTEN | awk '{print $4}' | sort)
if [ -f "$PORTS_CACHE" ]; then
  NEW_PORTS=$(diff "$PORTS_CACHE" <(echo "$CURRENT_PORTS") | grep "^>" | sed 's/^> //')
  if [ -n "$NEW_PORTS" ]; then
    log "ALERT: New listening ports: $NEW_PORTS"
    echo "New ports on $(hostname): $NEW_PORTS" | mail -s "[Security Alert] New Port" "$ALERT_EMAIL"
  fi
fi
echo "$CURRENT_PORTS" > "$PORTS_CACHE"

log "Security check completed"
EOF

chmod +x /usr/local/bin/security-monitor.sh
echo "*/15 * * * * root /usr/local/bin/security-monitor.sh" > /etc/cron.d/security-monitor

9. Hardening Verification Script

cat > /usr/local/bin/hardening-check.sh <<'EOF'
#!/bin/bash
echo "=== Linux Server Hardening Check ==="
echo ""

check() {
  local desc="$1"
  local cmd="$2"
  if eval "$cmd" &>/dev/null; then
    echo "OK  $desc"
  else
    echo "FAIL $desc"
  fi
}

echo "--- SSH ---"
check "Root login disabled" "grep -q '^PermitRootLogin no' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null"
check "Password auth disabled" "grep -q '^PasswordAuthentication no' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null"
check "Non-default SSH port" "! ss -tlnp | grep -q ':22 '"

echo ""
echo "--- Kernel ---"
check "ASLR enabled" "[ \$(sysctl -n kernel.randomize_va_space) -eq 2 ]"
check "SYN cookies enabled" "[ \$(sysctl -n net.ipv4.tcp_syncookies) -eq 1 ]"
check "IP forward disabled" "[ \$(sysctl -n net.ipv4.ip_forward) -eq 0 ]"
check "Redirects disabled" "[ \$(sysctl -n net.ipv4.conf.all.accept_redirects) -eq 0 ]"

echo ""
echo "--- Services ---"
check "auditd running" "systemctl is-active auditd"
check "fail2ban running" "systemctl is-active fail2ban"

echo ""
echo "--- MAC ---"
if command -v aa-status &>/dev/null; then
  check "AppArmor enabled" "aa-status --enabled"
elif command -v sestatus &>/dev/null; then
  check "SELinux enforcing" "[ \$(getenforce) = Enforcing ]"
fi

echo ""
echo "=== Check Complete ==="
EOF

chmod +x /usr/local/bin/hardening-check.sh
/usr/local/bin/hardening-check.sh

สรุป

Linux Server Hardening ที่ครบถ้วนต้องครอบคลุมหลายชั้น ตั้งแต่ User Permission, SSH Configuration, Kernel Parameters (sysctl), Filesystem Permissions, Network Services, Audit Logging, AppArmor/SELinux และการ Monitor อย่างต่อเนื่อง ไม่มี Hardening ใดที่สมบูรณ์ 100% แต่การทำ Defense-in-Depth ทำให้การโจมตีต้องผ่านหลายชั้นการป้องกัน ซึ่งเพิ่มโอกาสในการตรวจพบและหยุดยั้งการโจมตีได้ตั้งแต่เนิ่น ๆ

แนะนำบริการ DE

การทำ Server Hardening ตามขั้นตอนในบทความนี้ต้องการสิทธิ์ Root เต็มรูปแบบ Cloud VPS ของ DE ให้ Root Access สมบูรณ์ สามารถตั้งค่า sysctl, AppArmor, auditd, SSH Hardening และทุก Hardening Layer ได้อย่างอิสระ เหมาะสำหรับ Production Server ที่ต้องการความปลอดภัยสูง

สำหรับผู้ที่ต้องการโฮสต์เว็บไซต์โดยไม่ต้องดูแล Security Configuration เอง Cloud Hosting ของ DE มี Security Infrastructure ที่ตั้งค่าและดูแลไว้แล้ว รองรับทั้ง Web Application Firewall และการป้องกัน DDoS พื้นฐาน