การตั้งค่า Firewall ป้องกัน DDoS – 30 เมษายน 2569

จากฝันร้ายคืนวันศุกร์ สู่การวางระบบ Firewall รับมือ DDoS อย่างมืออาชีพ

การตั้งค่า Firewall ป้องกัน DDoS

Photo by isaac mijangos on Pexels

หากคุณเป็นคนที่ทำงานสาย System Admin หรือ DevOps คุณคงจะคุ้นเคยกับความรู้สึก “เสียวสันหลัง” เมื่อโทรศัพท์ดังขึ้นในคืนวันศุกร์เวลาสี่ทุ่ม พร้อมกับข้อความแจ้งเตือนจากระบบ Monitoring ว่า “Server Unreachable” ประสบการณ์ที่ผมกำลังจะเล่านี้ไม่ใช่เรื่องสมมติ แต่เป็นเหตุการณ์จริงที่ผมต้องเผชิญเมื่อปีก่อน เมื่อเว็บไซต์ E-commerce ของลูกค้าถูกถล่มด้วยการโจมตีแบบ DDoS (Distributed Denial of Service) จน Traffic พุ่งสูงขึ้นกว่า 100 เท่าในเวลาไม่กี่นาที

ในตอนนั้น ผมพยายามรีสตาร์ทเซอร์วิสทุกอย่างที่ขวางหน้า แต่มันก็เหมือนกับการพยายามวิดน้ำออกจากเรือที่ถูกคลื่นยักษ์ซัด ปัญหามันไม่ได้อยู่ที่โค้ดหรือฐานข้อมูล แต่อยู่ที่ “ประตูบ้าน” หรือ Firewall ของเราไม่ได้ถูกออกแบบมาเพื่อคัดกรองแขกที่ไม่ได้รับเชิญจำนวนมหาศาลขนาดนี้ บทความนี้ผมจึงอยากสรุปบทเรียนและวิธีการตั้งค่า Firewall ที่ผมใช้กู้สถานการณ์และนำมาปรับใช้เป็นมาตรฐานจนถึงปัจจุบัน

ความสับสนระหว่าง Traffic ปกติกับการโจมตี

สิ่งที่ยากที่สุดในช่วงแรกคือการแยกแยะว่าอันไหนคือลูกค้าที่กำลังกดซื้อของจริงๆ และอันไหนคือ Botnet การโจมตีที่เราเจอคือ HTTP Flood ซึ่งดูเหมือน Traffic ปกติมากจน Firewall แบบเดิมๆ แยกไม่ออก การตั้งค่าแบบ Default จึงไม่เพียงพออีกต่อไป เราจำเป็นต้องขยับไปใช้การคัดกรองที่ลึกถึงระดับ Layer 7 และการจำกัดอัตราการเชื่อมต่อในระดับ IP

1. การจำกัดอัตราการเชื่อมต่อด้วย Rate Limiting หัวใจสำคัญของการป้องกัน

กลยุทธ์แรกที่ผมนำมาใช้คือการทำ Rate Limiting ครับ เปรียบเสมือนการติดตั้งประตูหมุนที่อนุญาตให้คนเข้าได้ทีละคน หากใครพยายามวิ่งเข้าประตูมาพร้อมกันหลายๆ ครั้งในหนึ่งวินาที ระบบจะทำการบล็อกทันที วิธีนี้ช่วยป้องกันการโจมตีประเภท Brute Force และ HTTP Flood ได้อย่างชะงักนัก โดยเฉพาะในยุคที่ Botnet สามารถปลอมแปลง User-Agent ได้หลากหลาย

ผมเลือกใช้ Nginx เป็นด่านหน้าในการทำหน้าที่นี้ เพราะมันมีประสิทธิภาพสูงและกินทรัพยากรน้อยมาก การตั้งค่า limit_req_zone ช่วยให้เรากำหนดได้ว่าในหนึ่งวินาที หนึ่ง IP Address จะสามารถส่ง Request ได้กี่ครั้ง หากเกินกว่านั้น ระบบจะส่ง Error 503 กลับไปทันที ซึ่งช่วยรักษาทรัพยากรของ Application Server ด้านหลังไว้ได้

การตั้งค่า Nginx เพื่อรับมือการถล่ม Request

ในการใช้งานจริง เราต้องระวังไม่ให้ค่าที่ตั้งไว้นั้นเข้มงวดเกินไปจนบล็อกผู้ใช้งานทั่วไปที่อาจจะกด Refresh หน้าจอรัวๆ การใช้ burst parameter จึงเป็นตัวช่วยที่ดีในการอนุญาตให้มี Traffic เกินขีดจำกัดได้เล็กน้อยในช่วงเวลาสั้นๆ ก่อนที่จะเริ่มทำการบล็อกอย่างจริงจัง

http {
    # สร้าง zone สำหรับเก็บสถานะการเชื่อมต่อ ขนาด 10MB รองรับได้ประมาณ 160,000 IP
    limit_req_zone $binary_remote_addr zone=flood_limit:10m rate=10r/s;

    server {
        location /api/ {
            # จำกัดให้เข้าได้ 10 request ต่อวินาที และยอมให้มีคิวรอ (burst) ได้ 20 request
            limit_req zone=flood_limit burst=20 nodelay;
            proxy_pass http://backend_server;
        }
    }
}

2. การทำ IP Geoblocking เมื่อการโจมตีมาจากต่างแดน

ในคืนที่เกิดเหตุ ผมสังเกตเห็นจาก Log ว่า Traffic กว่า 90% มาจากประเทศที่เราไม่มีกลุ่มลูกค้าอยู่เลย เช่น รัสเซีย ยูเครน และบราซิล ในขณะที่ลูกค้าของเรา 100% อยู่ในประเทศไทย การเปิดรับ Traffic จากทั่วโลกในขณะที่โดนโจมตีจึงเป็นเรื่องที่ไม่สมเหตุสมผล การใช้ Geoblocking จึงเป็นวิธีที่ช่วยลดโหลดได้มหาศาลในพริบตา

ผมตัดสินใจใช้ GeoIP Module ในการตรวจสอบว่า IP ที่วิ่งเข้ามามาจากประเทศไหน หากไม่ใช่ประเทศไทย ผมจะสั่งให้ Firewall ทำการ DROP ทันที วิธีนี้ช่วยลดปริมาณ Traffic ที่เข้ามาถึงเซิร์ฟเวอร์ได้มากกว่า 70% ทำให้ทรัพยากรระบบเริ่มกลับมาหายใจได้คล่องขึ้นอีกครั้ง อย่างไรก็ตาม วิธีนี้ต้องใช้อย่างระมัดระวังหากบริการของคุณมีกลุ่มเป้าหมายเป็นชาวต่างชาติด้วย

การประยุกต์ใช้ร่วมกับ Cloudflare หรือ CDN

หากคุณใช้บริการอย่าง Cloudflare การทำ Geoblocking จะทำได้ง่ายและมีประสิทธิภาพยิ่งขึ้น เพราะมันจะทำการบล็อกตั้งแต่ที่ Edge Server ของเขา ทำให้ Traffic ขยะเหล่านั้นไม่วิ่งมาถึงท่ออินเทอร์เน็ตของเซิร์ฟเวอร์เราเลยแม้แต่นิดเดียว ช่วยประหยัด Bandwidth และค่าใช้จ่ายได้เป็นอย่างดี

3. การปรับแต่ง Iptables เพื่อป้องกัน SYN Flood ในระดับ Kernel

นอกจากการโจมตีในระดับ Application (Layer 7) แล้ว การโจมตีในระดับ Network (Layer 4) อย่าง SYN Flood ก็เป็นสิ่งที่เจอบ่อยมาก มันคือการที่ผู้โจมตีส่งคำขอเชื่อมต่อเข้ามาแต่ไม่ยอมทำการ Handshake ให้เสร็จ ทำให้เซิร์ฟเวอร์ต้องเปิดค้างไว้จน Resource เต็ม (Half-open connections) ผมต้องลงไปปรับแต่งที่ระดับ Kernel ของ Linux โดยตรง

การเปิดใช้งาน TCP SYN Cookies เป็นเทคนิคที่ฉลาดมาก มันช่วยให้เซิร์ฟเวอร์ไม่ต้องจองหน่วยความจำเพื่อรอการเชื่อมต่อที่ยังไม่สมบูรณ์ แต่จะส่งค่า Cookie กลับไปแทน หากเป็นการเชื่อมต่อจริง เครื่องลูกข่ายจะส่งค่านี้กลับมาเอง วิธีนี้ช่วยให้เซิร์ฟเวอร์ทนทานต่อการโจมตีแบบ SYN Flood ได้อย่างมหาศาลโดยที่ระบบไม่ค้าง

ตัวอย่างคำสั่งการตั้งค่า Kernel และ Iptables

นอกจากการปรับ Kernel แล้ว การใช้ Iptables เพื่อจำกัดการเชื่อมต่อใหม่ (New Connections) ต่อ IP ก็เป็นเรื่องที่ควรทำควบคู่กันไป เพื่อป้องกันไม่ให้ IP เดียวสร้างการเชื่อมต่อจำนวนมากเกินไปในเวลาอันสั้น

# เปิดใช้งาน SYN Cookies ในระดับ Kernel
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.tcp_max_syn_backlog=2048

# ใช้ Iptables จำกัดการเชื่อมต่อใหม่ต่อ IP (ไม่เกิน 20 connection ต่อนาที)
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 -j DROP

4. การใช้ Web Application Firewall (WAF) กรอง Packet ที่ผิดปกติ

หลังจากที่จัดการเรื่องปริมาณ Traffic ได้แล้ว ปัญหาต่อมาที่ผมเจอคือ “Bad Bots” ที่พยายามสแกนหาช่องโหว่ในระหว่างที่เรากำลังวุ่นวาย การมีแค่ Firewall ธรรมดาที่ดูแค่ IP และ Port นั้นไม่เพียงพอ เราต้องการสิ่งที่ฉลาดกว่านั้น นั่นคือ Web Application Firewall (WAF) ที่สามารถอ่านเนื้อหาใน HTTP Packet ได้

WAF จะช่วยตรวจสอบพฤติกรรมที่ผิดปกติ เช่น การพยายามฉีดคำสั่ง SQL (SQL Injection) หรือการส่ง Header ที่ดูประหลาดๆ ซึ่งมักจะมาพร้อมกับเครื่องมือโจมตีอัตโนมัติ ผมเลือกใช้ ModSecurity ร่วมกับ OWASP Core Rule Set ซึ่งช่วยสกัดกั้นการโจมตีที่ซับซ้อนได้โดยที่เราไม่ต้องเขียน Rule เองทั้งหมดตั้งแต่ต้น

การวิเคราะห์ Log เพื่อสร้าง Custom Rules

ไม่มี WAF ตัวไหนสมบูรณ์แบบ 100% จากประสบการณ์ของผม การหมั่นเข้าไปดู Access Log และ Error Log เป็นประจำจะช่วยให้เราเห็นรูปแบบการโจมตีใหม่ๆ เช่น การเรียกใช้งานไฟล์ wp-login.php ถี่ๆ ทั้งที่ระบบเราไม่ได้ใช้ WordPress เราสามารถเขียน Rule สั้นๆ เพื่อบล็อกพฤติกรรมเหล่านี้ได้ทันที

5. การทำ Monitoring และ Alerting ระบบเตือนภัยล่วงหน้า

บทเรียนที่สำคัญที่สุดที่ผมได้รับคือ “เราไม่สามารถป้องกันสิ่งที่เรามองไม่เห็นได้” ในคืนที่เกิดเหตุ ผมรู้ตัวช้าไปเกือบ 15 นาทีเพราะไม่มีระบบแจ้งเตือนที่รวดเร็วพอ หลังจากเหตุการณ์นั้น ผมจึงให้ความสำคัญกับการทำ Real-time Monitoring อย่างมาก โดยใช้เครื่องมืออย่าง Prometheus และ Grafana มาช่วยวาดกราฟให้เห็นภาพชัดเจน

เราตั้งค่า Alert ให้ส่งข้อความเข้า Telegram ทันทีเมื่อค่าเฉลี่ยของ Request ต่อวินาทีพุ่งสูงเกินเกณฑ์ปกติ หรือเมื่อมีอัตรา Error 5xx สูงขึ้นผิดปกติ การรู้ตัวเร็วช่วยให้เราสามารถเปิดใช้งานโหมด “Under Attack” บน Cloudflare หรือปรับแต่ง Firewall ได้ทันท่วงทีก่อนที่ระบบจะล่มจริง

การเตรียมแผนรับมือ (Incident Response Plan)

นอกเหนือจากเครื่องมือ การมี “ขั้นตอน” ที่ชัดเจนก็สำคัญไม่แพ้กัน ใครจะเป็นคนตัดสินใจบล็อก IP ประเทศไหน ใครจะเป็นคนติดต่อ ISP หรือ Cloud Provider การมี Check-list ในมือจะช่วยลดความตื่นตระหนกเมื่อเกิดเหตุการณ์จริง และทำให้การแก้ปัญหาเป็นไปอย่างมีระบบ

  • Rate Limiting: จำกัดจำนวน Request ต่อ IP เพื่อป้องกันการถล่มเซิร์ฟเวอร์
  • Geoblocking: ปิดกั้น Traffic จากประเทศที่ไม่ใช่กลุ่มเป้าหมายในช่วงที่โดนโจมตี
  • Kernel Tuning: เปิดใช้งาน SYN Cookies เพื่อป้องกันการโจมตีระดับ Network Layer
  • WAF: ใช้ Web Application Firewall กรอง Traffic ที่มีพฤติกรรมเป็นอันตราย
  • Monitoring: ติดตั้งระบบแจ้งเตือนที่รวดเร็วเพื่อให้รู้ตัวก่อนระบบจะล่ม

สรุป

การป้องกัน DDoS ไม่ใช่เรื่องของการตั้งค่าครั้งเดียวแล้วจบไป แต่มันคือการปรับตัวและเรียนรู้อย่างต่อเนื่อง จากเหตุการณ์คืนวันศุกร์ในครั้งนั้น ทำให้ผมเข้าใจว่าความปลอดภัยของระบบไม่ได้ขึ้นอยู่กับ Firewall ราคาแพงเพียงอย่างเดียว แต่ขึ้นอยู่กับการออกแบบระบบที่ยืดหยุ่น การตั้งค่าที่เหมาะสมกับพฤติกรรมผู้ใช้ และการมีระบบ Monitoring ที่แม่นยำ

หากคุณกำลังดูแลระบบอยู่ อย่ารอให้เกิดเหตุการณ์ล่มก่อนแล้วค่อยเริ่มป้องกันครับ การเริ่มตั้งค่า Rate Limiting พื้นฐาน หรือการทำ Hardening Kernel ในวันนี้ อาจจะเป็นสิ่งที่ช่วยให้คุณได้นอนหลับเต็มอิ่มในคืนวันศุกร์หน้าก็ได้ หวังว่าประสบการณ์และตัวอย่าง Code ที่ผมแชร์จะมีประโยชน์กับเพื่อนร่วมสายงานทุกท่านครับ

Leave a Reply

Your email address will not be published. Required fields are marked *