Thời gian gần đây, cộng đồng frontend liên tục bàn luận về một số lỗ hổng bảo mật mới được công bố liên quan đến Next.js và React. Đây không chỉ là các lỗi nhỏ trong quá trình triển khai, mà là những rủi ro có thể ảnh hưởng trực tiếp đến hệ thống production nếu không xử lý kịp thời. Trong bài viết này, chúng ta sẽ phân tích những nhóm lỗi bảo mật gần đây, cơ chế hình thành, tác động thực tế và hướng khắc phục.

1. Tóm tắt các lỗi bảo mật nổi bật
Trong 12 tháng gần đây, có 3 nhóm vấn đề chính xuất hiện trong hệ sinh thái React và Next.js:
1.1. RCE thông qua Route Handlers / Server Actions
Một số phiên bản Next.js (với App Router) từng gặp vấn đề khi Server Actions hoặc Route Handlers bị lộ ra môi trường client hoặc bị gọi sai cách, tạo điều kiện cho attacker chèn dữ liệu không hợp lệ và thực thi code phía server.
Nguyên nhân chính:
-
Serialize/deserialization chưa chặt chẽ
-
Dev chỉ khóa bảo mật ở client, không khóa server
-
Upload file nhưng không validate đầu vào
-
Server Action để public nhưng lại thao tác với file hệ thống
Tác động:
-
Remote Code Execution
-
Lộ thông tin môi trường
-
Ghi đè file hoặc leo quyền
1.2. XSS từ React Server Components (RSC)
RSC giúp loại bỏ nhiều nguy cơ XSS nhờ auto-escape, nhưng gần đây nhiều báo cáo cho thấy:
-
Một số package hoặc middleware render HTML thô không được escape
-
Một số cách dùng dangerouslySetInnerHTML kết hợp RSC và hydrate sai cách tạo ra XSS chéo
-
Dev dùng Markdown parser không an toàn trong môi trường RSC
Điểm đáng sợ:
-
XSS chạy cả client và ảnh hưởng đến quá trình hydrate.
-
Có thể đánh cắp token hoặc session.
1.3. Lộ dữ liệu thông qua Next.js Caching
Hệ thống caching mới của Next.js (bao gồm Static Rendering + Route Cache + fetch cache) có thể dẫn đến:
-
User A nhận dữ liệu của User B vì cache chia sẻ
-
Thông tin nhạy cảm bị cache nhầm dưới dạng static
-
API route bị cache vĩnh viễn do thiếu config
Điều này xảy ra khi:
-
Dùng fetch() nhưng quên cache: "no-store"
-
Dùng revalidate trên API nhạy cảm
-
Render server-side nhưng vẫn bị đóng băng kết quả trong node runtime
Kết quả:
-
Data leakage
-
Vi phạm bảo mật và sai chuẩn GDPR/PDPA
2. Tại sao lỗi xuất hiện ngày càng nhiều?
Có 3 lý do chính:
2.1. Next.js tiến hóa quá nhanh
Từ Pages Router → App Router → Server Actions → RSC → TurboPack → Partial Prerender…
Mỗi bước đều kéo theo những thay đổi lớn về runtime, serialization, cache, và boundary giữa client – server.
Tốc độ phát triển vượt quá khả năng nắm bắt của phần lớn lập trình viên.
2.2. Mô hình Server Actions gây nhầm lẫn
Ranh giới “client gọi server” tưởng rõ nhưng lại có nhiều ngách:
-
Khi nào được serialize?
-
Dữ liệu nào được phép đưa vào props?
-
Hàm server có bị lộ không?
Chỉ cần dev để lộ 1 function không nên public, attacker chỉ việc gọi endpoint là xong.
2.3. Tư duy lập trình frontend cũ không còn phù hợp
Nhiều dev React quen:
-
đặt logic ở client
-
render HTML thủ công
-
dùng library mà không quan tâm escaping
Nhưng môi trường RSC hiện đại buộc dev phải suy nghĩ như backend engineer.
3. Ảnh hưởng đến hệ thống production
Nếu không cập nhật bản vá hoặc không cấu hình đúng, bạn có thể gặp các rủi ro sau:
3.1. RCE & kiểm soát server
Attacker có thể:
-
ghi file
-
đọc toàn bộ project
-
thực thi shell command
-
lấy ENV file
Đây là mức nguy hiểm cao nhất.
3.3. Chiếm quyền session
Thông qua XSS trong quá trình hydrate, attacker có thể:
-
đánh cắp cookie
-
lấy access token
-
giả mạo tài khoản
4. Cách kiểm tra và phòng tránh ngay lập tức
4.1. Kiểm tra phiên bản Next.js
Luôn cập nhật bản vá, đặc biệt khi Next.js phát hành bản liên quan bảo mật.
npm outdated next
4.2. Bảo vệ API & Server Actions
-
Không public Server Actions mặc định
-
Validate mọi input:
import { z } from "zod";
const schema = z.object({ name: z.string().min(1) });
-
Không thao tác file hệ thống trực tiếp trong action public
4.3. Chặn XSS triệt để
-
Không dùng dangerouslySetInnerHTML khi không bắt buộc
-
Nếu dùng Markdown → chọn parser an toàn như marked + DOMPurify
-
Luôn escape HTML trước khi render
4.4. Cấu hình cache đúng cách
Trong API nhạy cảm:
export async function GET() {
return new Response("...", { headers: { "Cache-Control": "no-store" }});
}
Hoặc với fetch:
await fetch(url, { cache: "no-store" });
5. Khuyến nghị cho Dev, Tech Lead và doanh nghiệp
Dành cho dev
-
Học lại mô hình server-first thay vì client-first
-
Kiểm tra kỹ boundary giữa RSC và Client Component
-
Không copy code từ stackoverflow mà không hiểu cơ chế
Dành cho Tech Lead
-
Quy định rõ coding style khi dùng App Router
-
Bật eslint-plugin-next bảo mật
-
Setup CI để kiểm tra leak dữ liệu hoặc use-case không an toàn
Dành cho doanh nghiệp
-
Lập lịch audit 6 tháng một lần
-
Tách code RSC, API và server runtime rõ ràng
-
Bắt buộc dùng TypeScript, Zod/Yup và kiểm tra input chuẩn hóa
Kết luận
Next.js và React đang phát triển cực nhanh, kéo theo nhiều thay đổi về cách ứng dụng web vận hành. Những lỗi bảo mật mới không xuất phát từ bản thân framework, mà thường đến từ cách dev sử dụng chưa đúng với mô hình mới.
Việc hiểu đúng cơ chế, cập nhật bản vá và đặt bảo mật làm ưu tiên hàng đầu là chìa khóa để vận hành ứng dụng an toàn trong môi trường hiện đại.







