กลับไปที่บล็อก
27 ตุลาคม 2568Sergei Solod9 นาทีในการอ่าน

เว็บ Next.js แบบสแตติกของผมโดนสแกนช่องโหว่นับพันครั้งต่อวัน แต่ Nginx แทบไม่สะเทือน

ในล็อกมี probe ที่ตามหา WordPress, PHP backdoor, .env และ .git/config เต็มไปหมด แต่บนสแตก Next.js แบบสแตติก + Nginx ของผม ส่วนใหญ่จบเป็น miss และ 404 ที่มีต้นทุนต่ำ ขณะที่โหลด CPU ไม่เปลี่ยนในช่วงที่สังเกต นี่คือสิ่งที่ประสบการณ์นี้บอกได้จริงเกี่ยวกับความปลอดภัยของเว็บสแตติก และสิ่งที่มันไม่ได้พิสูจน์

ความปลอดภัยNext.jsNginxDevOpsStatic HostingAttack Surface

ทุกวัน server log ของผมบันทึกการสแกนหาช่องโหว่อัตโนมัตินับพันครั้ง ตัว request เองดูน่ากังวลไม่น้อย:

  • /wp-admin/wp.php
  • /111.php
  • /code.php
  • /.git/config
  • /i.php
  • /admin
  • /api/.env
  • /kal.php

สิ่งที่ทำให้ผมแปลกใจไม่ใช่จำนวน แต่คือ server แทบไม่ตอบสนองต่อมันเลย ระหว่างที่ผมเฝ้าดู traffic นี้ โหลด CPU ไม่มีการเปลี่ยนแปลงที่มองเห็นได้

ข้อสังเกตนั้นเป็นเรื่องจริง แต่คำอธิบายเดิมของผมเด็ดขาดเกินไป Static delivery ไม่ใช่โล่วิเศษ และ 404 ก็ไม่ได้ฟรี ข้อดีจริงของ architecture ผมเฉพาะเจาะจงกว่านั้น: probe แบบ opportunistic จำนวนมากมีต้นทุนต่ำ เพราะใน public request path แทบไม่มี server-side application logic ให้มันไปถึง

นี่คือ probe ไม่ใช่หลักฐานว่าระบบถูกเจาะ

เมื่อเห็น /wp-admin/wp.php หรือ /111.php เราอาจเรียกทุก request ว่า “exploit” ได้ง่าย ๆ แต่ในทางเทคนิคไม่แม่นนัก สิ่งที่ผมเห็นเป็นหลักคือ automated probing: bot ลอง filename และ endpoint ที่พบบ่อย แล้วดูว่าอะไรตอบกลับ

บาง path เล็ง WordPress หรือ PHP ชัดเจน ส่วน /.git/config และ /api/.env พยายามหา configuration หรือ secret ที่อาจถูกเผยแพร่โดยไม่ได้ตั้งใจ /admin ยิ่ง generic กว่าและอาจเป็น route ปกติของเว็บได้ Request ที่น่าสงสัยบอกผมว่า scanner กำลังหาอะไร ไม่ได้พิสูจน์ว่ามี vulnerability นั้นจริง

ในกรณีของผม จุดสำคัญคือ architecture: เว็บสาธารณะเป็น HTML แบบสแตติกที่ pre-render ด้วย Next.js และเสิร์ฟตรงจาก Nginx

ทำไม traffic นี้จึงมีต้นทุนต่ำบน stack ของผม

สำหรับหน้าที่ผมพูดถึง ไม่มี PHP runtime หรือ database อยู่หลังทุก request Nginx เสิร์ฟไฟล์ที่มีอยู่แล้ว หาก scanner ขอ /111.php แต่ไม่มีไฟล์นั้น ก็ไม่มี PHP application เริ่มทำงาน ไม่มี WordPress code ถูก execute และไม่มี database query Request แค่ miss แล้วจบด้วย 404

ตรงนี้เปลี่ยน cost model ของ request ใน dynamic application คำขอหนึ่งอาจผ่าน routing, framework, authentication, rendering, database หรือ service อื่น ๆ แต่ static path ของผมมี moving parts น้อยกว่ามาก Nginx ยังต้องรับ connection, process HTTP, หา resource, เขียน log และส่ง response อยู่ เพียงแต่งานระดับ application น้อย

ผมยังใช้ aggressive caching กับเว็บ ซึ่งช่วยการส่ง static content ตามปกติ แต่ผมจะไม่ยกเครดิตให้ cache สำหรับ random 404 ทุกครั้ง URI ปลอมที่ไม่เคยเห็นมาก่อนอาจยังผ่าน processing ปกติของ Nginx และ filesystem lookup ก่อนคืน 404

ข้อแก้ไขสำคัญ: static ไม่ได้แปลว่า “ปลอดภัยโดยนิยาม”

นี่คือส่วนที่วันนี้ผมจะเขียนให้ระมัดระวังกว่าเดิม Static architecture เอา server-side component หลายอย่างออกจาก public request path แต่ไม่ได้ทำให้งาน security หายไป

  • ไฟล์ที่ expose ก็ยัง expose อยู่. ถ้า .git, .env, backup หรือ secret หลุดเข้า public directory และ configuration ไม่บล็อก Nginx ก็สามารถเสิร์ฟมันได้มีประสิทธิภาพเหมือน HTML
  • Nginx, TLS, OS และ network ยังอยู่ใน attack surface. ต้อง patch และ configure ให้เหมาะสม
  • Client-side code ยังมี vulnerability ได้. Static HTML ไม่ได้ทำให้ JavaScript, auth logic ใน browser หรือ third-party script ปลอดภัยโดยอัตโนมัติ
  • Resource exhaustion ยังเกิดได้. Connection, bandwidth, TLS handshake, worker capacity, log I/O และ disk space มีขีดจำกัด Traffic ที่มากพอสามารถกระทบเว็บสแตติกได้

ดังนั้นข้อสรุปที่ถูกต้องไม่ใช่ “request เหล่านี้ไม่มีความหมาย” แต่คือ probe ที่เจาะจงกับ application จำนวนมากไม่มีอะไรให้ execute ใน architecture นี้

“นับพัน scan ต่อวัน” อาจฟังน่ากลัวกว่าภาระจริง

Log ทำให้ Internet background noise ดูรุนแรง เพราะ failed probe ทุกอันกลายเป็นหนึ่งบรรทัด แต่ยอดต่อวันเพียงอย่างเดียวไม่ได้บอก operational impact คำขอไม่กี่พันที่กระจายตลอด 24 ชั่วโมงต่างจากจำนวนเท่ากันที่มาใน burst สั้น ๆ มาก

CPU ก็เป็นเพียง signal หนึ่ง ในกรณีของผม CPU คงที่ ซึ่งเป็น evidence ที่ดีว่า traffic นี้ไม่ได้สร้าง compute pressure ที่เห็นได้ชัดในช่วงที่สังเกต แต่ไม่ได้พิสูจน์ว่าค่าใช้จ่ายใน resource อื่นเป็นศูนย์ หากจะประเมินจริง ผมจะดู request rate, bandwidth, active connections, Nginx worker utilization, response latency, log volume และ disk usage ด้วย

สิ่งที่ผมเรียนรู้จาก noise นี้

บทเรียนสำคัญที่สุดสำหรับผมคือ architecture สามารถทำให้การโจมตีอัตโนมัติทั้งกลุ่มแทบไม่เกี่ยวข้องได้ โดยไม่ต้องเขียน rule แยกสำหรับ scanner signature ทุกแบบ Bot จะหา WordPress และ PHP backdoor ทั้งวันก็ได้ ถ้า public request path ไม่มีทั้งสองอย่าง probe เหล่านั้นก็แทบไม่มีอะไรใช้ประโยชน์

แต่ตอนนี้ผมไม่เอา “ไม่เกี่ยวกับ stack ของผม” ไปเท่ากับ “traffic ที่ harmless” แล้ว Checklist ปัจจุบันของผมคือ:

  • รู้ว่า runtime และ service ใด reachable จริงจาก public request path
  • เก็บ secret, repository metadata, backup และ build artifact นอก web root หรือ block อย่างชัดเจน
  • มอง repeated 404 probe เป็น Internet background noise ปกติ จนกว่าจะมี evidence อื่นเรื่อง targeting หรือ impact
  • อย่าตัดสินว่า abusive traffic ฟรีจาก CPU เพียงอย่างเดียว
  • Patch Nginx, OS, TLS library และ dependency ต่อให้ application เป็น static

สิ่งที่ประสบการณ์นี้ไม่ได้พิสูจน์

ผมไม่ได้ทำ controlled benchmark และไม่ได้จำลอง DDoS ผมเพียงสังเกต production logs กับ server load ขณะที่มี scanner requests นับพันเข้ามาทุกวัน เท่านี้เพียงพอสำหรับข้อสรุปเชิงปฏิบัติกับ setup ของผม แต่ไม่ใช่หลักฐานของกฎสากลว่า “static ชนะเสมอ”

สิ่งที่ผมยืนยันได้อย่างแม่นยำกว่าคือ: ใน Next.js static export ของผมที่ Nginx เป็นคนเสิร์ฟ scanner traffic ส่วนใหญ่ที่เห็นจบเป็น file miss และ 404 ต้นทุนต่ำ แทนที่จะไปถึง PHP runtime หรือ database-backed application และระหว่างสังเกตโหลด CPU ไม่เปลี่ยน

นี่คือข้อดีด้าน resilience ที่ผมสนใจจริง ๆ Moving parts ที่น้อยลงไม่ได้ทำให้ระบบ invulnerable แต่ทำให้ random Internet noise มีจุดน้อยลงที่จะเปลี่ยนเป็นงาน application จริง