ตั้ง Security Headers บน Nginx ให้ได้เกรด A
HTTP Security Headers คือ response headers ที่บอก browser ว่าควรปฏิบัติกับ content อย่างไร ช่วยป้องกัน XSS, Clickjacking, MIME sniffing และ information leakage เพิ่มได้ใน Nginx ไม่กี่บรรทัด แต่ผลลัพธ์คือความปลอดภัยขึ้นอย่างมีนัยสำคัญ
Security Headers ที่จำเป็น
สร้างไฟล์ snippet แยกเพื่อ include ในทุก site:
sudo nano /etc/nginx/snippets/security-headers.conf
# ป้องกัน Clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# ป้องกัน MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# ป้องกัน XSS บน browser เก่า
add_header X-XSS-Protection "1; mode=block" always;
# บังคับ HTTPS (ตั้งหลังจากมี SSL แล้ว)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ควบคุม Referrer
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# จำกัด browser features
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# ซ่อน Nginx version
server_tokens off;
# Include ใน server block ของแต่ละ site
sudo nano /etc/nginx/sites-available/example.com
server {
...
include snippets/security-headers.conf;
...
}
Content Security Policy (CSP)
CSP เป็น header ที่ซับซ้อนที่สุดแต่ให้ประโยชน์มากที่สุด กำหนดว่า browser โหลด resource จากที่ไหนได้บ้าง:
# CSP พื้นฐาน (เริ่มจาก report-only ก่อน)
add_header Content-Security-Policy-Report-Only
"default-src 'self';
script-src 'self' 'unsafe-inline' https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self';
frame-ancestors 'self';" always;
Content-Security-Policy-Report-Only ก่อนเสมอ — header นี้บอก browser ให้ report violations ไปที่ console แต่ยังไม่ block จริง ทำให้ทดสอบได้ว่า CSP จะทำให้อะไรพัง แล้วค่อยเปลี่ยนเป็น Content-Security-Policy จริง
ปิด Information Leakage
sudo nano /etc/nginx/nginx.conf
http {
# ซ่อน Nginx version
server_tokens off;
# ซ่อน PHP version ใน header (ต้องตั้งใน php.ini ด้วย)
# expose_php = Off
}
# ลบ header X-Powered-By ที่ PHP ส่งมา
fastcgi_hide_header X-Powered-By;
proxy_hide_header X-Powered-By;
ตรวจสอบว่า Security Headers ทำงานถูกต้อง
# ตรวจ headers ที่ส่งออก
curl -sI https://example.com | grep -iE "x-frame|x-content|strict-transport|referrer|permissions|x-xss"
# ทดสอบ nginx config
sudo nginx -t
# Reload nginx
sudo systemctl reload nginx
# ตรวจด้วย securityheaders.com (ออนไลน์)
curl -s "https://api.securityheaders.com/?q=https://example.com&hide=on" | python3 -m json.tool
แก้ปัญหาที่พบบ่อย
CSP ทำให้ CSS/JS ไม่โหลด
CSP block resource ที่ไม่อยู่ใน whitelist ดู violation ใน browser console แล้วเพิ่ม domain นั้นเข้า policy:
# ดู CSP violations ใน Chrome DevTools Console
# หรือเพิ่ม report-uri เพื่อรับ report
add_header Content-Security-Policy
"default-src 'self'; report-uri /csp-report" always;
HSTS ทำให้เข้าเว็บ HTTP ไม่ได้
HSTS บอก browser ว่า domain นี้ต้องใช้ HTTPS เท่านั้น เมื่อตั้งแล้ว browser จะไม่ยอม HTTP อีก ต้องมี SSL certificate ที่ valid ก่อน:
# ถ้าต้องการถอน HSTS (ต้องรอ max-age หมด หรือล้าง browser cache)
# เปลี่ยน max-age เป็น 0 แล้ว reload
add_header Strict-Transport-Security "max-age=0" always;
X-Frame-Options ทำให้ iframe ของตัวเองใช้ไม่ได้
SAMEORIGIN อนุญาต iframe จาก domain เดียวกัน แต่ถ้าต้องการอนุญาต domain อื่นด้วยให้ใช้ CSP frame-ancestors แทน:
# ใช้ CSP frame-ancestors แทน X-Frame-Options
# (รองรับหลาย domain และ flexible กว่า)
add_header Content-Security-Policy "frame-ancestors 'self' https://trusted-partner.com" always;
add_header หายไปใน location block
Nginx: ถ้า location block มี add_header ของตัวเอง มันจะ override header ทั้งหมดจาก parent ต้องประกาศซ้ำหรือใช้ always flag และ include snippet:
location /api/ {
include snippets/security-headers.conf; # include ซ้ำ
add_header Cache-Control "no-store" always;
...
}
คำถามที่พบบ่อย
HSTS preload ต่างจาก HSTS ปกติอย่างไร?
HSTS ปกติ browser จำ policy หลังจากเคยเยี่ยมชม HSTS preload คือ domain ถูกใส่ใน browser's built-in list ล่วงหน้า ทำให้ browser บังคับ HTTPS ตั้งแต่ครั้งแรกที่เข้าก็ตาม ต้อง submit ที่ hstspreload.org และต้องมี includeSubDomains; preload ใน header
Content-Security-Policy ยากเกินไป จะเริ่มจากตรงไหน?
เริ่มจาก default-src 'self' แล้วดู console errors เพื่อ whitelist ทีละอัน หรือใช้เครื่องมือ CSP evaluator ของ Google ที่ csp-evaluator.withgoogle.com ช่วย audit policy ที่มีอยู่
Security headers มีผลต่อ SEO ไหม?
ไม่มีผลโดยตรงกับ ranking แต่ HTTPS (ที่บังคับด้วย HSTS) เป็น ranking signal ของ Google และ CSP/security headers บางตัวช่วยป้องกันไม่ให้เว็บถูก blacklist ซึ่งมีผลต่อ SEO มาก