🔵 Node.js

วิธีเพิ่มความปลอดภัยให้ API ด้วย Helmet, CORS และ Rate Limit สำหรับมือใหม่

10 นาที 14 views บันทึกเป็น PDF
วิธีเพิ่มความปลอดภัยให้ API ด้วย Helmet, CORS และ Rate Limit สำหรับมือใหม่

มือใหม่หัดเขียน API ต้องรู้! มาดูวิธีป้องกันช่องโหว่ด้วย Helmet, CORS และ Express Rate Limit เพื่อให้แอปของคุณปลอดภัยจากการโจมตีและใช้งานได้จริง

ทำไม API ต้องมีการรักษาความปลอดภัย

เวลาเราสร้างแอปพลิเคชันขึ้นมาสักตัว เรามักจะโฟกัสไปที่การเขียนฟีเจอร์ให้ใช้งานได้จริง แต่ในฐานะโปรแกรมเมอร์มือใหม่ เราต้องไม่ลืมเรื่อง Security Best Practices (แนวปฏิบัติที่ดีที่สุดด้านความปลอดภัย) เพราะ API (ช่องทางสื่อสารระหว่างซอฟต์แวร์) ของเราเปรียบเสมือนประตูบ้านที่เปิดทิ้งไว้ให้คนแปลกหน้าเข้ามาได้ตลอดเวลา

ลองนึกภาพว่าบ้านของคุณไม่มีกลอนประตู ไม่มีรั้ว และไม่มีใครคอยตรวจบัตรประชาชนที่หน้าบ้าน ใครจะเดินเข้ามาหยิบของหรือทำลายข้าวของในบ้านคุณก็ได้ การทำ API ให้ปลอดภัยก็เหมือนกับการติดตั้งกล้องวงจรปิด ติดตั้งสัญญาณกันขโมย และมีรปภ. คอยคัดกรองคนเข้าออก เพื่อให้ข้อมูลของผู้ใช้งานปลอดภัยจากการโจมตีของเหล่าแฮกเกอร์

ถ้าเราละเลยเรื่องนี้ ข้อมูลส่วนตัวของผู้ใช้งานอาจรั่วไหล หรือเซิร์ฟเวอร์ (เครื่องคอมพิวเตอร์ที่เก็บข้อมูลและทำงานให้เรา) อาจถูกถล่มจนล่มใช้งานไม่ได้ การเรียนรู้วิธีป้องกันตั้งแต่เนิ่นๆ จะช่วยให้เราเป็นโปรแกรมเมอร์ที่เขียนโค้ดอย่างมืออาชีพ และสร้างความมั่นใจให้กับคนที่มาใช้งานซอฟต์แวร์ของเราได้เป็นอย่างดี

ป้องกันการโจมตีด้วย Helmet (HTTP Headers)

Helmet (หมวกกันน็อค) คือเครื่องมือที่จะช่วยเซตค่า HTTP Headers (ข้อมูลส่วนหัวที่ส่งไปพร้อมกับข้อมูลหลัก เพื่อบอกรายละเอียดว่าข้อมูลนี้มาจากไหนหรือต้องจัดการอย่างไร) ให้มีความปลอดภัยมากขึ้นโดยอัตโนมัติ ซึ่งเป็นเรื่องที่มือใหม่มักจะมองข้ามไปเพราะมันทำงานอยู่เบื้องหลังตลอดเวลา

ปกติแล้วเวลาเบราว์เซอร์ (โปรแกรมที่ใช้เข้าเว็บ) ติดต่อกับ API ของเรา มันจะมีการส่งข้อมูลเล็กๆ น้อยๆ ติดไปด้วย ซึ่งแฮกเกอร์อาจใช้ช่องโหว่ตรงนี้เพื่อสวมรอยหรือฝังโค้ดอันตรายเข้ามา การใช้ helmet จะช่วยปิดช่องโหว่เหล่านี้ เช่น การป้องกันการถูกแอบอ้างชื่อเว็บไซต์หรือการโดนฝังเนื้อหาแปลกปลอมลงบนหน้าเว็บ

การติดตั้งทำได้ง่ายมากด้วยคำสั่ง npm install helmet ในโปรเจกต์ Node.js (ระบบที่ช่วยให้เราเขียน JavaScript ฝั่งเซิร์ฟเวอร์ได้) ของเรา หลังจากนั้นเราแค่เรียกใช้มันเป็น Middleware (ซอฟต์แวร์ตัวกลางที่คอยดักจับหรือจัดการคำขอ ก่อนจะส่งไปถึงโค้ดหลัก) เพียงไม่กี่บรรทัดในไฟล์เซิร์ฟเวอร์ของเรา

// นำเข้า express และ helmet
const express = require('express');
const helmet = require('helmet');
const app = express();

// เรียกใช้ helmet เป็น middleware เพื่อป้องกันช่องโหว่พื้นฐาน
app.use(helmet());

app.get('/', (req, res) => {
  res.send('API ปลอดภัยขึ้นแล้ว');
});

ในโค้ดชุดนี้ เราทำการดึง helmet เข้ามาใช้งานและสั่ง app.use(helmet()) เพื่อให้มันเริ่มทำงานกับทุกคำขอที่เข้ามายัง API ของเรา บรรทัดที่สำคัญคือการเรียกใช้ app.use ซึ่งจะทำให้ทุกเส้นทางใน API ของเราได้รับความคุ้มครองทันที

เมื่อรันเซิร์ฟเวอร์แล้ว ถ้าคุณลองเช็กที่ Network Tab (แถบแสดงการรับส่งข้อมูลในเครื่องมือสำหรับนักพัฒนาของเบราว์เซอร์) คุณจะพบว่าใน Response Headers จะมีค่าความปลอดภัยเพิ่มขึ้นมา เช่น X-Content-Type-Options หรือ Content-Security-Policy ซึ่งช่วยยืนยันว่า API ของเรากำลังใส่ใจความปลอดภัยอยู่

จัดการสิทธิ์การเข้าถึงด้วย CORS

CORS (การแชร์ทรัพยากรข้ามแหล่งกำเนิด) เป็นกลไกที่เบราว์เซอร์ใช้ควบคุมว่า เว็บไซต์จากโดเมนอื่นสามารถมาดึงข้อมูลจาก API ของเราได้หรือไม่ หากเราไม่ตั้งค่านี้ให้ดี คนอื่นอาจจะดึงข้อมูลของเราไปใช้ในทางที่ผิด หรือในทางกลับกัน เราก็อาจจะเรียกใช้ API ของคนอื่นไม่ได้เลย

ลองจินตนาการว่าคุณมีสมุดบันทึกวางไว้บนโต๊ะ ถ้าคุณไม่กำหนดกฎเกณฑ์เลย ใครเดินผ่านไปมาก็อาจจะมาเปิดอ่านหรือขีดเขียนอะไรลงไปก็ได้ การใช้ cors จึงเป็นการกำหนดว่า "อนุญาตให้เฉพาะเว็บไซต์ที่เรารู้จักเท่านั้นนะ ถึงจะเข้ามาอ่านข้อมูลใน API นี้ได้"

สำหรับการพัฒนาในช่วงแรก เราอาจจะตั้งค่าให้เข้าถึงได้จากทุกที่ แต่เมื่อต้องเอาขึ้น Production (สภาพแวดล้อมที่ใช้งานจริงสำหรับผู้ใช้ทั่วไป) เราต้องเปลี่ยนมาอนุญาตเฉพาะโดเมนของเว็บเราเท่านั้น เพื่อป้องกันไม่ให้คนอื่นแอบอ้างนำ API ของเราไปใช้บนเว็บไซต์ของเขาเอง

const cors = require('cors');

// อนุญาตเฉพาะโดเมนที่ระบุเท่านั้น
const corsOptions = {
  origin: 'https://my-awesome-app.com' 
};

app.use(cors(corsOptions));

ในตัวอย่างนี้ เรากำหนดค่า corsOptions โดยระบุ origin (แหล่งกำเนิด) ให้ชัดเจนว่าอนุญาตให้แค่เว็บไซต์ของเราเท่านั้นที่เรียกใช้ได้ หากมีเว็บอื่นพยายามเรียกใช้ เบราว์เซอร์จะบล็อกการเชื่อมต่อให้ทันทีตามกฎที่เราตั้งไว้

ผลลัพธ์ที่ได้คือ เมื่อเราพยายามยิงคำขอ API จากเว็บไซต์อื่นที่ไม่ใช่ my-awesome-app.com เบราว์เซอร์จะแสดงข้อผิดพลาดเกี่ยวกับ CORS ในคอนโซล ทำให้มั่นใจได้ว่าข้อมูลของเราถูกเข้าถึงโดยผู้ที่ได้รับอนุญาตจริงๆ เท่านั้น

ป้องกัน Brute Force ด้วย express-rate-limit

Brute Force (การสุ่มเดารหัสผ่านหรือข้อมูลจำนวนมากในเวลาอันสั้น) คือวิธีที่แฮกเกอร์ใช้เพื่อพยายามเจาะระบบโดยการสุ่มรหัสผ่านไปเรื่อยๆ จนกว่าจะถูก การมี express-rate-limit (เครื่องมือจำกัดจำนวนคำขอ) จะช่วยหยุดการโจมตีแบบนี้ได้โดยการจำกัดว่าในหนึ่งนาที ห้ามยิงคำขอเกินกี่ครั้ง

เปรียบเหมือนมีคนพยายามจะหมุนลูกบิดประตูบ้านคุณรัวๆ เป็นร้อยครั้งต่อวินาที ถ้าคุณเป็นเจ้าของบ้าน คุณคงจะล็อกประตูและห้ามคนนั้นเข้าใกล้บ้านอีกสักพัก express-rate-limit ทำหน้าที่แบบนั้นเลย คือถ้าใครทำตัวน่าสงสัย ก็จะโดนจำกัดสิทธิ์ชั่วคราว

การใช้งานเครื่องมือนี้เป็นเรื่องที่สำคัญมากสำหรับหน้า Login (เข้าสู่ระบบ) หรือหน้าสมัครสมาชิก เพราะเป็นจุดที่แฮกเกอร์มักจะเล็งเป้าหมายเพื่อสุ่มข้อมูล หากเราไม่ป้องกันไว้ ระบบเราอาจจะค้างหรือข้อมูลผู้ใช้หลุดได้ง่ายๆ

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // กำหนดช่วงเวลา 15 นาที
  max: 100 // จำกัดให้ทำได้แค่ 100 ครั้งต่อ 15 นาที
});

app.use('/api/', limiter);

โค้ดส่วนนี้กำหนดว่าในทุกเส้นทางที่ขึ้นต้นด้วย /api/ จะถูกจำกัดไว้ที่ 100 ครั้งต่อ 15 นาที หากใครพยายามเกินกว่านี้ เซิร์ฟเวอร์จะตอบกลับด้วยข้อผิดพลาด 429 Too Many Requests (คำขอมากเกินไป) ทันที

เมื่อคุณลองทดสอบด้วยการยิงคำขอรัวๆ เกินจำนวนที่กำหนด คุณจะเห็นว่าเซิร์ฟเวอร์ปฏิเสธการทำงานและส่งสถานะ 429 กลับมา ซึ่งนี่คือสัญญาณว่าระบบป้องกันของเราทำงานได้อย่างถูกต้องและกำลังปกป้อง API จากการโดนยิงถล่มอยู่

ทำความสะอาดข้อมูลด้วย Sanitization

Sanitization (การทำให้ข้อมูลสะอาด) คือขั้นตอนการกรองข้อมูลที่ผู้ใช้ส่งเข้ามา เพื่อป้องกันไม่ให้มีโค้ดอันตรายแฝงตัวเข้ามาทำลายระบบ โดยเฉพาะการโจมตีที่เรียกว่า Injection (การใส่คำสั่งแปลกปลอมเข้าไปในฐานข้อมูล) ซึ่งอาจทำให้ข้อมูลในระบบของเราเสียหายทั้งหมด

ลองนึกภาพว่าคุณเปิดรับพัสดุจากคนแปลกหน้า แต่คุณมีเครื่องสแกนที่หน้าบ้านเพื่อตรวจดูว่าข้างในมีระเบิดหรือสิ่งของอันตรายหรือไม่ ถ้าเจอสิ่งของอันตราย คุณก็แค่ทิ้งมันไปก่อนจะนำเข้าบ้าน การทำ Sanitization ก็คือการสแกนข้อมูลที่รับมาจาก req.body (ข้อมูลที่ส่งมาพร้อมกับคำขอ) นั่นเอง

ใน Node.js เรามักใช้ไลบรารีอย่าง express-validator เพื่อช่วยตรวจสอบและทำความสะอาดข้อมูล ไม่ว่าจะเป็นการตัดแท็ก HTML หรือการตรวจสอบรูปแบบข้อมูลให้ถูกต้องก่อนจะนำไปเก็บลงในฐานข้อมูล เพื่อป้องกันไม่ให้แฮกเกอร์ฝังคำสั่งรันโค้ดลงบนเซิร์ฟเวอร์ของเรา

const { body, validationResult } = require('express-validator');

app.post('/register', 
  body('username').trim().escape(), // ตัดช่องว่างและแปลงอักขระพิเศษ
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
    // ทำงานต่อได้ถ้าข้อมูลสะอาดแล้ว
  }
);

ในตัวอย่างนี้ เราใช้ trim() เพื่อเอาช่องว่างหน้าหลังออก และ escape() เพื่อแปลงตัวอักษรพิเศษอย่าง < หรือ > ให้กลายเป็นข้อความธรรมดา เพื่อไม่ให้มันถูกมองว่าเป็นคำสั่งของโปรแกรม

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

สรุป: เริ่มต้นสร้างความปลอดภัยตั้งแต่วันนี้

การทำให้ API ปลอดภัยไม่ได้มีอะไรซับซ้อนเกินกว่าความพยายามของเรา แค่เริ่มต้นจากสิ่งพื้นฐานที่เราคุยกันไป ไม่ว่าจะเป็นการใช้ helmet ปิดช่องโหว่ทั่วไป การตั้งค่า cors ให้ถูกที่ การจำกัดคำขอด้วย express-rate-limit และการตรวจความสะอาดของข้อมูลด้วย Sanitization ทุกอย่างล้วนเป็นกำแพงป้องกันที่สำคัญ

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

จงจำไว้ว่าความปลอดภัยคือส่วนหนึ่งของฟีเจอร์ ไม่ใช่สิ่งที่ทำทีหลังได้ การฝึกทำตามแนวทางเหล่านี้จะทำให้พอร์ตโฟลิโอของคุณดูน่าเชื่อถือและพร้อมสำหรับการทำงานจริงในอนาคต ขอให้สนุกกับการเขียนโค้ดและสร้างสรรค์ซอฟต์แวร์ที่ปลอดภัยให้กับโลกใบนี้ครับ

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

คู่มือการทำ Production Deployment: รันโปรเจกต์ด้วย PM2 และ Docker ให้เสถียรเหมือนมือโปร
Node.js

คู่มือการทำ Production Deployment: รันโปรเจกต์ด้วย PM2 และ Docker ให้เสถียรเหมือนมือโปร

เรียนรู้วิธีนำโปรเจกต์ขึ้นเซิร์ฟเวอร์จริงให้รันได้ 24 ชั่วโมงด้วย PM2 และใช้ Docker ช่วยคุมสภาพแวดล้อมให้เหมือนกันทุกเครื่อง ลดปัญหาโค้ดพังเมื่อย้ายที่

1 week ago 11 นาที
15 views
เปลี่ยนโปรเจกต์ Node.js เป็น TypeScript: วิธีตั้งค่าและใช้งานสำหรับมือใหม่
Node.js

เปลี่ยนโปรเจกต์ Node.js เป็น TypeScript: วิธีตั้งค่าและใช้งานสำหรับมือใหม่

อยากเปลี่ยนจาก Node.js มาใช้ TypeScript แต่ไม่รู้เริ่มยังไง? บทความนี้สอนตั้งค่า tsconfig.json, การรันด้วย tsx และการทำ Type Checking ให้ Express แบบเข้าใจง่าย

1 week ago 9 นาที
12 views
สอนเขียน Automated Testing ด้วย Jest และ Supertest สำหรับมือใหม่
Node.js

สอนเขียน Automated Testing ด้วย Jest และ Supertest สำหรับมือใหม่

เลิกทดสอบโค้ดด้วยมือแบบเดิม ๆ มาหัดเขียน Automated Testing ด้วย Jest และ Supertest เพื่อเช็กฟังก์ชันและ API ให้ทำงานถูกต้องแม่นยำ ลดบั๊กกวนใจ

1 week ago 9 นาที
15 views