ตั้งค่า HTTP Security Headers ให้เว็บไซต์
HTTP Security Headers คือคำสั่งที่เซิร์ฟเวอร์ส่งไปพร้อมหน้าเว็บ เพื่อบอกเบราว์เซอร์ว่าควรป้องกันผู้ใช้อย่างไร เช่น ต้องใช้ HTTPS เสมอ ห้ามนำหน้าเว็บไปฝังใน iframe ของเว็บอื่น หรือห้ามเดาชนิดไฟล์เอง Header เหล่านี้ไม่ได้แทนการอัปเดตระบบหรือเขียนโค้ดให้ปลอดภัย แต่ช่วยปิดช่องทางโจมตีฝั่งเบราว์เซอร์หลายแบบ เช่น Clickjacking และ XSS บางรูปแบบ
บทความนี้อธิบาย Header ที่ควรมี ความหมาย ค่าที่แนะนำ และวิธีตั้งบน Nginx, Apache, Plesk และ IIS พร้อมข้อควรระวังที่ทำให้เว็บพังได้ถ้าตั้งเร็วเกินไป
สิ่งที่ต้องเตรียม
- เว็บไซต์ที่ใช้ HTTPS ได้สมบูรณ์แล้ว (ทุกหน้าและทุก Subdomain ที่เกี่ยวข้อง)
- สิทธิ์แก้ไฟล์ตั้งค่า Web Server หรือไฟล์
.htaccessหรือสิทธิ์เข้า Plesk - สำเนาไฟล์ตั้งค่าเดิม และช่วงเวลาที่ทดสอบเว็บได้หลังเปลี่ยน
Header ที่แนะนำและความหมาย
| Header | ค่าที่แนะนำเป็นจุดเริ่มต้น | ป้องกันอะไร |
|---|---|---|
Strict-Transport-Security | max-age=300 แล้วค่อยเพิ่มเป็น max-age=31536000 | บังคับให้เบราว์เซอร์ใช้ HTTPS เสมอ ป้องกันการดักเปลี่ยนเป็น HTTP |
X-Content-Type-Options | nosniff | ห้ามเบราว์เซอร์เดาชนิดไฟล์ เช่นตีความไฟล์ข้อความเป็นสคริปต์ |
X-Frame-Options | SAMEORIGIN | Clickjacking โดยห้ามเว็บอื่นนำหน้าเราไปฝังใน iframe |
Referrer-Policy | strict-origin-when-cross-origin | ไม่ส่ง URL เต็ม (ซึ่งอาจมีข้อมูลส่วนตัว) ไปให้เว็บอื่น |
Permissions-Policy | camera=(), microphone=(), geolocation=() | ปิดการใช้ฟีเจอร์ของเบราว์เซอร์ที่เว็บไม่ได้ใช้ |
Content-Security-Policy | เริ่มแบบ Content-Security-Policy-Report-Only | กำหนดว่าโหลดสคริปต์ รูป ฟอนต์ จากที่ไหนได้บ้าง ลดผลกระทบของ XSS |
Header X-XSS-Protection เลิกใช้แล้ว เบราว์เซอร์รุ่นปัจจุบันไม่รองรับ ไม่จำเป็นต้องตั้ง ถ้าเครื่องมือตรวจบางตัวแนะนำ ให้ตั้งเป็น 0 หรือไม่ตั้งเลย ส่วน X-Frame-Options ใช้ร่วมกับ frame-ancestors 'self' ใน CSP ได้ เบราว์เซอร์รุ่นใหม่จะยึด CSP เป็นหลัก
ขั้นตอนที่ 1: ตรวจ Header ที่มีอยู่ตอนนี้
curl -sI https://example.com/
ดูว่ามี Header ใดในตารางอยู่แล้วบ้าง เพราะแผงควบคุม, ปลั๊กอินความปลอดภัย หรือ CDN อาจส่งมาให้แล้ว ถ้าตั้งซ้ำ เบราว์เซอร์จะได้รับสองค่า ซึ่งบาง Header (เช่น CSP) จะถูกนำมาใช้ร่วมกันแบบเข้มขึ้นจนเว็บพังได้
ขั้นตอนที่ 2: ตั้งค่าบน Nginx
ใส่ในบล็อก server { } ที่ฟัง 443 ของเว็บ
add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
คำว่า always ทำให้ส่ง Header แม้หน้าตอบกลับเป็น Error เช่น 404 หรือ 500
ข้อควรระวังที่พบบ่อยที่สุด: ถ้าบล็อก location ใดมี add_header ของตัวเอง (เช่นตั้ง Cache-Control ให้ไฟล์รูป) Header ทั้งหมดจากระดับ server จะไม่ถูกส่งใน location นั้นเลย วิธีแก้คือเก็บ Header ไว้ในไฟล์แยก แล้ว include ทั้งในระดับ server และใน location ที่มี add_header ของตัวเอง
sudo nano /etc/nginx/snippets/security-headers.conf
ย้ายบรรทัด add_header ทั้งห้าบรรทัดข้างต้นไปไว้ในไฟล์นี้ ในบล็อก server เหลือเพียง include snippets/security-headers.conf; และใน location ที่มี Header ของตัวเองให้เขียนแบบนี้
location ~* \.(jpg|jpeg|png|webp|svg|css|js)$ {
include snippets/security-headers.conf;
add_header Cache-Control "public, max-age=2592000";
}
ตรวจและโหลดค่าใหม่
sudo nginx -t
sudo systemctl reload nginx
บน AlmaLinux/Rocky ไม่มีโฟลเดอร์ snippets มาให้ สร้างเองด้วย sudo mkdir -p /etc/nginx/snippets แล้ว include ด้วย Path เต็ม
ขั้นตอนที่ 3: ตั้งค่าบน Apache หรือไฟล์ .htaccess
ต้องเปิดโมดูล mod_headers ก่อน บน Ubuntu ใช้
sudo a2enmod headers
sudo systemctl reload apache2
บน AlmaLinux/Rocky โมดูลนี้เปิดอยู่แล้ว ตรวจด้วย httpd -M | grep headers จากนั้นใส่ใน Virtual Host หรือด้านบนของไฟล์ .htaccess
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=300"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
ใช้ set ไม่ใช่ add เพื่อแทนที่ค่าเดิมแทนการส่งซ้ำ ถ้าแก้ Virtual Host ให้รัน apachectl configtest ก่อน reload
ขั้นตอนที่ 4: บน Plesk และ IIS
บน Plesk ที่เปิด Proxy mode ใช้วิธีของ Apache ใน .htaccess ได้ หรือไปที่ Websites & Domains เลือกโดเมน เปิด Apache & nginx Settings แล้วใส่คำสั่ง add_header ในช่อง Additional nginx directives ส่วน HSTS อาจตั้งจากส่วนขยาย SSL It! ได้ในบางเวอร์ชัน ถ้าตั้งที่นั่นแล้ว อย่าตั้งซ้ำในที่อื่น
บน IIS ใส่ในไฟล์ web.config ของเว็บ
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
</customHeaders>
</httpProtocol>
</system.webServer>
หรือตั้งผ่าน IIS Manager ที่ไอคอน HTTP Response Headers ของเว็บ สำหรับ HSTS บน IIS 10 รุ่น Windows Server 2019 ขึ้นไป ตั้งได้ในหน้าตั้งค่า HSTS ของ Site
ขั้นตอนที่ 5: เพิ่ม HSTS อย่างระมัดระวัง
HSTS ถูกจดจำในเบราว์เซอร์ของผู้เข้าชมตามจำนวนวินาทีที่กำหนด ถ้าตั้งไว้หนึ่งปีแล้ววันหนึ่ง HTTPS ใช้ไม่ได้ (เช่นใบรับรองหมดอายุ) ผู้เข้าชมจะกดข้ามคำเตือนไม่ได้เลย จึงควรเพิ่มทีละขั้น
- เริ่มที่
max-age=300(5 นาที) ทดสอบทุกหน้า - เพิ่มเป็น
max-age=86400(1 วัน) แล้วmax-age=2592000(30 วัน) - เมื่อมั่นใจแล้วจึงใช้
max-age=31536000(1 ปี) - ใส่
includeSubDomainsเฉพาะเมื่อ ทุก Subdomain ใช้ HTTPS ได้ รวมถึง Subdomain ภายในอย่างmail.example.com preloadทำให้ชื่อโดเมนถูกฝังในเบราว์เซอร์ ถอนออกได้ยากและใช้เวลานาน ใส่เฉพาะเมื่อตั้งใจจริงเท่านั้น
ดูวิธีเฝ้าวันหมดอายุของใบรับรองได้ที่ ตรวจสอบ SSL Certificate และวันหมดอายุ
ขั้นตอนที่ 6: เริ่ม Content-Security-Policy แบบ Report-Only
CSP ทรงพลังที่สุดแต่ก็ทำให้เว็บพังง่ายที่สุด เพราะต้องระบุทุกแหล่งที่เว็บโหลดสคริปต์ เช่น Google Analytics, Tag Manager, แชต หรือแผนที่ เริ่มจากโหมดรายงานก่อน ซึ่งเบราว์เซอร์จะแจ้งเตือนใน Console แต่ไม่บล็อกจริง
add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data: https:; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'" always;
เปิดหน้าเว็บหลายๆ หน้า แล้วดูข้อความ Content-Security-Policy ในแท็บ Console ของ DevTools เพิ่มแหล่งที่ถูกต้องลงใน Policy จนไม่มีข้อความเตือน จากนั้นจึงเปลี่ยนชื่อ Header เป็น Content-Security-Policy ให้มีผลจริง เว็บ WordPress ที่ใช้ปลั๊กอินจำนวนมากมักต้องใช้เวลาปรับนาน ถ้าเวลาจำกัด ตั้งเฉพาะ frame-ancestors 'self' ไว้ก่อนก็ได้ประโยชน์แล้ว
ตรวจสอบผลลัพธ์
curl -sI https://example.com/ | grep -iE 'strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy|content-security'
ควรเห็นแต่ละ Header เพียงหนึ่งบรรทัด ทดสอบกับไฟล์รูปหรือ CSS และกับหน้าที่ไม่มีอยู่จริงด้วย เพื่อยืนยันว่า Header ถูกส่งในทุกกรณี
curl -sI https://example.com/wp-content/themes/x/style.css | grep -i x-content-type
curl -sI https://example.com/not-found-test | grep -i x-frame
จากนั้นเปิดเว็บในเบราว์เซอร์ ทดลองฟังก์ชันสำคัญ เช่น ฟอร์มติดต่อ, ตะกร้าสินค้า, หน้าชำระเงิน และหลังบ้าน
ปัญหาที่พบบ่อย
Header หายไปในบางไฟล์ (Nginx)
เป็นเรื่องการสืบทอด add_header ที่อธิบายในขั้นตอนที่ 2 ให้ include ไฟล์ Header ในทุก location ที่มี add_header ของตัวเอง
ฟีเจอร์ที่ฝังจากเว็บอื่นใช้ไม่ได้
ถ้าเว็บของคุณต้องถูกฝังใน iframe ของอีกโดเมนหนึ่ง (เช่นระบบจองที่ฝังในเว็บพาร์ทเนอร์) SAMEORIGIN จะบล็อก ให้ลบ X-Frame-Options แล้วใช้ CSP frame-ancestors 'self' https://partner.example.net แทน
ตั้ง HSTS แล้ว Subdomain เข้าไม่ได้
เกิดจากใส่ includeSubDomains ขณะที่บาง Subdomain ยังไม่มี SSL แก้โดยติดตั้ง SSL ให้ Subdomain นั้น การลดค่า max-age จะมีผลกับผู้เข้าชมเมื่อเบราว์เซอร์ของเขากลับมาเยี่ยมชมผ่าน HTTPS อีกครั้งเท่านั้น
Header เป็นเพียงส่วนหนึ่งของความปลอดภัย ดูภาพรวมเพิ่มเติมได้ที่ เช็กลิสต์ความปลอดภัยเว็บไซต์ WordPress หากต้องการความช่วยเหลือ ติดต่อทีมงาน THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/
- Categories:
- Cloud
- Tags:
- Cloud
- Cloud Server
หมวดหมู่ที่น่าสนใจ
- Account Settings
- AD Server
- AI
- Alibaba Cloud
- Anti-Spam Gateway
- AWS Amazon Web Services
- Campaign
- CentOS/AlmaLinux
- Cloud
- Cloud Backup
- Cloud Communication
- Cloud Migration
- Cloud Security
- Cloud Server Management
- Cloud Solution
- Cloud Solution for Government
- Cloud Solutions by Industry
- Cloud Storage
- Cloud VPS App Plus +
- Cloud VPS DirectAdmin
- Cloud VPS Plesk
- CSR
- Cyber Security
- Cybersecurity
- Data Sovereignty
- Database Server
- DDoS
- Digital Tranformation
- Digital Transformation
- Direct Mail
- Directadmin
- Domainname
- Ecommerce
- ERP
- Generative AI
- Getting Started
- Google Cloud
- Google G Suite
- Huawei Cloud
- IT News
- Linux Server
- Managed Cloud Services
- Managed Service Provider
- Manual
- Microsoft
- Microsoft 365
- Microsoft Azure
- News
- On-premise
- Private Mail Server
- Promotion
- Recommend Solution (Enterprise)
- Server
- Sovereign Cloud
- THAI DATA CLOUD Platform
- Ubuntu
- Ubuntu
- Uncategorized
- VMware
- VPS Server
- Web Design
- Web Hosting
- Web Hosting (DirectAdmin)
- Web Hosting (Plesk)
- Web Technologies
- Windows Server
- Wordpress
- Zimbra
- เรื่องราวความประทับใจ
- โซลูชันสำหรับธุรกิจการผลิตและยานยนต์
- โซลูชันสำหรับธุรกิจการศึกษา
- โซลูชันสำหรับธุรกิจการเงิน
- โซลูชันสำหรับธุรกิจขนส่งและกระจายสินค้า
- โซลูชันสำหรับธุรกิจค้าปลีก
- โซลูชันสำหรับธุรกิจท่องเที่ยว
- โซลูชันสำหรับธุรกิจบริการสุขภาพและโรงพยาบาล
- โซลูชันสำหรับธุรกิจประกันภัย
- โซลูชันสำหรับธุรกิจพลังงานและสาธารณูปโภค
- โซลูชันสำหรับธุรกิจสื่อสารมวลชนและเอ็นเตอร์เทนเมนท์
- โซลูชันสำหรับธุรกิจอสังหาริมทรัพย์
- โซลูชันสำหรับธุรกิจเทคโนโลยี


