ข้ามไปเนื้อหาหลัก

Category: reference

HTTP Security Headers — ป้องกันเว็บด้วย Headers

รายการ HTTP security headers ที่ควรตั้งค่าสำหรับเว็บใดก็ตาม ครอบคลุม CSP, HSTS, X-Frame-Options, Permissions-Policy และวิธีตั้งค่าใน Astro + Railway

· อ่านประมาณ 2 นาที

สารบัญ

ทำไม Security Headers สำคัญ

Browser รองรับ headers ที่ป้องกันการโจมตีหลายรูปแบบ แต่ถ้าไม่ตั้งค่า server จะไม่ส่งมาให้ browser — ทำให้เว็บเสี่ยงโดยไม่จำเป็น:

  • XSS (Cross-Site Scripting) — script จากแหล่งไม่ทราบที่รันใน browser ผู้ใช้
  • Clickjacking — เว็บอื่นฝัง site ในกรอบ <iframe> เพื่อหลอก user
  • MITM (Man-in-the-Middle) — ดักจับ HTTP traffic ก่อน upgrade เป็น HTTPS

Headers ที่สำคัญ

Content-Security-Policy (CSP)

ควบคุมว่า browser จะโหลด resource จากที่ไหนได้บ้าง:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; object-src 'none'
Directiveความหมาย
default-src 'self'โหลดได้เฉพาะจาก origin เดียวกัน (fallback)
script-src 'self'JS จาก origin เดียวเท่านั้น — บล็อก inline script
style-src 'unsafe-inline'อนุญาต inline CSS (จำเป็นสำหรับ Astro)
object-src 'none'บล็อก Flash และ plugins ทั้งหมด
frame-ancestors 'none'ห้ามฝังใน iframe

Strict-Transport-Security (HSTS)

บังคับให้ browser ใช้ HTTPS เสมอ ไม่มีทาง fallback ไป HTTP:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • max-age=31536000 — จำ 1 ปี
  • includeSubDomains — ครอบคลุม subdomain ทั้งหมด
  • preload — รวมอยู่ใน browser preload list

X-Frame-Options

ป้องกัน clickjacking:

X-Frame-Options: DENY

หรือใช้ CSP frame-ancestors แทน (ยืดหยุ่นกว่า):

Content-Security-Policy: frame-ancestors 'none'

X-Content-Type-Options

ป้องกัน MIME sniffing:

X-Content-Type-Options: nosniff

Browser จะไม่เดา content type — ต้องใช้ MIME type ที่ server ส่งมาเท่านั้น

Referrer-Policy

ควบคุม referrer header ที่ส่งไปเมื่อคลิก external link:

Referrer-Policy: strict-origin-when-cross-origin

ส่ง full URL เมื่อ navigate ภายใน origin เดียวกัน แต่ส่งเฉพาะ origin เมื่อออกไป site อื่น

Permissions-Policy

ควบคุมการเข้าถึง browser features:

Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()

ปิด camera, microphone, location, และ FLoC ทั้งหมด — เว็บ content ไม่ต้องการ feature เหล่านี้

ตั้งค่าใน Railway (railway.json)

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS"
  },
  "deploy": {
    "startCommand": "node server.js",
    "headers": {
      "/*": {
        "X-Content-Type-Options": "nosniff",
        "X-Frame-Options": "DENY",
        "Referrer-Policy": "strict-origin-when-cross-origin",
        "Permissions-Policy": "camera=(), microphone=(), geolocation=()",
        "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
      }
    }
  }
}

ตั้งค่าผ่าน _headers file (Netlify / Cloudflare Pages)

/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:; object-src 'none'

ทดสอบ Headers

เครื่องมือที่ใช้ตรวจสอบ:

  • securityheaders.com — ใส่ URL แล้วได้ grade และรายการปัญหา
  • Mozilla Observatory — วิเคราะห์ละเอียดกว่า พร้อมคำแนะนำ
  • curl -I https://panupongws.com — ดู response headers โดยตรง

สำหรับ static site ทั่วไป เป้าหมายคือ Grade A บน securityheaders.com โดยไม่ทำให้ฟีเจอร์ปกติพัง