Mã do AI tạo ra hoạt động. Nó chạy. Nó trông đúng. Nó cũng đi kèm với năm lỗ hổng bảo mật giống nhau trong hầu hết mọi dự án. Đây không phải là những rủi ro lý thuyết — chúng là những lỗ hổng cụ thể xuất hiện trong hầu hết mọi codebase được tạo bởi Claude, Cursor, Replit hoặc Copilot khi bạn không yêu cầu bảo mật một cách rõ ràng.
Tôi đã kiểm tra hàng chục dự án vibe-coded trong năm qua, và năm lỗi tương tự xuất hiện trong ít nhất 80% trong số đó. Mỗi lỗi chỉ mất dưới 30 phút để sửa. Dưới đây là những gì cần tìm và cách sửa chính xác.
Lỗi 1: Khóa API được mã hóa cứng trong mã Frontend
Cách nó xảy ra: Bạn yêu cầu Claude "kết nối với Supabase" hoặc "thêm thanh toán Stripe," và nó tạo mã có khóa API được dán trực tiếp vào thành phần React. Mã hoạt động hoàn hảo — và khóa bí mật của bạn hiển thị cho bất kỳ ai mở DevTools của trình duyệt và kiểm tra tab Network hoặc nguồn JavaScript.
Tại sao nó nguy hiểm: Khóa service role của Supabase của bạn vượt qua tất cả bảo mật cơ sở dữ liệu. Khóa bí mật Stripe của bạn cho phép ai đó tính phí thẻ hoặc phát hành hoàn tiền. Khóa OpenAI của bạn cho phép ai đó tích lũy hàng nghìn đô la trong lệnh gọi API trên tài khoản của bạn. Các bot chủ động quét các kho công cộng GitHub và các trang được triển khai để tìm các khóa bị lộ.
Cách sửa: Di chuyển mọi bí mật đến các biến môi trường. Trong Next.js, chỉ các biến bắt đầu bằng NEXT_PUBLIC_ mới đến trình duyệt. Bất kỳ khóa nào cấp quyền ghi, quyền truy cập quản trị viên hoặc quyền truy cập tài chính phải chỉ trên máy chủ.
Sau khi di chuyển khóa đến .env.local, hãy tìm kiếm toàn bộ codebase của bạn cho các giá trị khóa cũ để đảm bảo chúng biến mất. Sau đó kiểm tra lịch sử Git của bạn — nếu khóa từng được cam kết, nó vẫn còn trong lịch sử repo của bạn ngay cả khi bạn xóa nó. Tạo lại (xoay vòng) bất kỳ khóa nào từng bị lộ, thậm chí là tạm thời.
Thời gian sửa: 15–30 phút.
Lỗi 2: Bảng Supabase không có Bảo mật ở cấp độ hàng
Cách nó xảy ra: AI tạo các truy vấn tạo bảng Supabase và các hoạt động CRUD, nhưng không bật Bảo mật ở cấp độ hàng (RLS). Theo mặc định, các bảng Supabase với RLS bị tắt hoàn toàn có thể truy cập bởi bất kỳ ai có URL dự án của bạn và khóa anon — cả hai đều công khai (và nên là).
Tại sao nó nguy hiểm: Không có RLS, Người dùng A có thể truy vấn dữ liệu của Người dùng B. Một lệnh gọi fetch đơn giản từ bảng điều khiển trình duyệt có thể kéo mọi hàng từ mọi bảng. Toàn bộ cơ sở dữ liệu của bạn hiệu quả là công khai.
Cách phát hiện: Đi tới bảng điều khiển Supabase của bạn → Trình chỉnh sửa bảng. Nếu bất kỳ bảng nào hiển thị "RLS Disabled," bạn có vấn đề này. Cũng kiểm tra xem mã phía khách hàng của bạn có sử dụng khóa service_role thay vì khóa anon không — đó còn tồi tệ hơn.
Cách sửa: Bật RLS trên mỗi bảng. Sau đó tạo chính sách phù hợp với các mẫu truy cập của ứng dụng của bạn. Chính sách phổ biến nhất: người dùng chỉ có thể SELECT, INSERT, UPDATE và DELETE các hàng trong đó auth.uid() = user_id. Kiểm tra bằng cách đăng nhập dưới dạng một người dùng và cố gắng truy cập dữ liệu của người dùng khác thông qua REST API của Supabase.
Thời gian sửa: 30–60 phút tùy thuộc vào số lượng bảng.
Nhận được giá trị từ điều này? Chúng tôi xuất bản một bài phân tích sâu mỗi tuần về các công cụ AI, quy trình làm việc và hướng dẫn bảo mật thực tế. Tham gia những người đọc lấy nó trước tiên →
Lỗi 3: Không xác thực đầu vào trên biểu mẫu hoặc tuyến API
Cách nó xảy ra: AI tạo các biểu mẫu chấp nhận bất kỳ đầu vào nào và các tuyến API tin tưởng bất kỳ dữ liệu nào đến. Biểu mẫu có thuộc tính "required" trong HTML, nhưng không có xác thực phía máy chủ. Ai đó bỏ qua biểu mẫu hoàn toàn bằng cách gửi yêu cầu API trực tiếp với bất kỳ tải nào họ muốn.
Tại sao nó nguy hiểm: Không có xác thực phía máy chủ, những kẻ tấn công có thể tiêm các tập lệnh vào cơ sở dữ liệu của bạn (XSS được lưu trữ), gửi tải quá lớn làm sập máy chủ của bạn hoặc gửi dữ liệu phá vỡ logic ứng dụng của bạn (như giá âm hoặc trường email chứa SQL).
Cách phát hiện: Mở bất kỳ tuyến API hoặc hành động máy chủ nào trong codebase của bạn. Nếu nó sử dụng req.body hoặc dữ liệu biểu mẫu mà không kiểm tra hình dạng, loại và độ dài của mỗi trường, bạn có vấn đề này.
Cách sửa: Thêm xác thực phía máy chủ vào mỗi điểm cuối bằng một thư viện xác thực lược đồ. Zod là tiêu chuẩn cho các dự án TypeScript:
import { z } from 'zod';
const taskSchema = z.object({
title: z.string().min(1).max(200),
description: z.string().max(2000).optional(),
priority: z.enum(['low', 'medium', 'high']),
});
// In your API route:
const parsed = taskSchema.safeParse(req.body);
if (!parsed.success) {
return Response.json({ error: parsed.error }, { status: 400 });
}
Đối với bất kỳ trường nào hiển thị dưới dạng HTML (bình luận, mô tả, tiểu sử), cũng khử trùng đầu ra bằng DOMPurify trước khi hiển thị nó.
Thời gian sửa: 30–60 phút.
Lỗi 4: Không giới hạn tốc độ trên các điểm cuối API
Cách nó xảy ra: AI không bao giờ thêm giới hạn tốc độ trừ khi bạn yêu cầu nó. Mỗi tuyến API mà ứng dụng của bạn hiển thị có thể bị hit hàng nghìn lần mỗi giây bởi bất kỳ ai có một tập lệnh.
Tại sao nó nguy hiểm: Không có giới hạn tốc độ, ai đó có thể tấn công bằng brute-force điểm cuối đăng nhập của bạn, quét cơ sở dữ liệu của bạn bằng cách hit các điểm cuối danh sách nhiều lần, làm quá tải máy chủ của bạn (từ chối dịch vụ) hoặc đốt cháy hạn ngạch API của bạn nếu các điểm cuối của bạn gọi các dịch vụ bên ngoài như OpenAI hoặc Stripe.
Cách phát hiện: Nếu không có tuyến API nào của bạn kiểm tra có bao nhiêu yêu cầu một IP hoặc người dùng duy nhất đã thực hiện gần đây, bạn không có giới hạn tốc độ.
Cách sửa: Cách tiếp cận đơn giản nhất cho các ứng dụng được lưu trữ trên Vercel là một bộ giới hạn tốc độ trong bộ nhớ cho phát triển và một dựa trên Redis cho sản xuất. Edge Middleware của Vercel có thể xử lý giới hạn tốc độ cơ bản. Upstash Redis (bản miễn phí) với @upstash/ratelimit cung cấp cho bạn giới hạn tốc độ cấp độ sản xuất với một lượng mã nhỏ.
Điểm xuất phát hợp lý: 60 yêu cầu mỗi phút cho người dùng được xác thực, 20 mỗi phút cho người dùng chưa xác thực và 5 mỗi phút cho các điểm cuối đăng nhập/đăng ký (để ngăn chặn brute forcing).
Thời gian sửa: 20–45 phút.
Lỗi 5: Thiếu kiểm tra xác thực trên các trang được bảo vệ và API
Cách nó xảy ra: AI tạo một trang bảng điều khiển đẹp và các tuyến API trả về dữ liệu người dùng, nhưng không thêm middleware để xác minh người dùng thực sự đã đăng nhập. Trang "hoạt động" vì trong phát triển bạn luôn đăng nhập. Trong sản xuất, ai đó có thể truy cập URL bảng điều khiển trực tiếp mà không cần đăng nhập hoặc hit điểm cuối API và nhận dữ liệu trở lại.
Tại sao nó nguy hiểm: Truy cập không được xác thực vào các trang được bảo vệ có nghĩa là bất kỳ ai cũng có thể thấy các bảng điều khiển người dùng, bảng điều khiển quản trị hoặc dữ liệu riêng tư chỉ bằng cách đoán URL. Các tuyến API không được bảo vệ có nghĩa là bất kỳ công cụ nào như Postman hoặc curl có thể kéo dữ liệu mà không cần thông tin xác thực.
Cách phát hiện: Mở một cửa sổ trình duyệt ẩn danh (không đăng nhập) và điều hướng trực tiếp đến bảng điều khiển, cài đặt hoặc URL quản trị của bạn. Nếu bạn có thể thấy bất kỳ nội dung nào mà không được chuyển hướng đến trang đăng nhập, bạn có vấn đề này. Sau đó hãy cố gắng hit các tuyến API của bạn trực tiếp — nếu chúng trả về dữ liệu mà không có cookie phiên hợp lệ hoặc mã thông báo xác thực, những tuyến đó không được bảo vệ.
Cách sửa: Thêm middleware xác thực chạy trước mỗi tuyến được bảo vệ. Trong Next.js App Router, tạo middleware.ts ở gốc dự án của bạn:
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const session = request.cookies.get('session');
if (!session) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*', '/api/protected/:path*'],
};
Điều chỉnh phù hợp để bao gồm mỗi tuyến cần xác thực. Kiểm tra trong chế độ ẩn danh sau khi triển khai.
Thời gian sửa: 15–30 phút.
Cách ngăn chặn những điều này trong các dự án tương lai
Mô hình rõ ràng: AI tạo mã hoạt động về mặt chức năng nhưng bỏ qua bảo mật vì bạn không yêu cầu nó. Cách khắc phục là yêu cầu nó ngay từ đầu.
Thêm cái này vào cuối lời nhắc ban đầu của bạn cho bất kỳ dự án vibe-coded nào:
SECURITY REQUIREMENTS:
- All secrets in environment variables (never hardcoded)
- Supabase RLS enabled on all tables with per-user policies
- Server-side input validation on every API route (use Zod)
- Rate limiting on all public endpoints
- Authentication middleware on all protected routes
- No service role key in client-side code
Điều này sẽ không bắt được mọi thứ, nhưng nó loại bỏ năm lỗ hổng phổ biến nhất trong lần chuyển đầu tiên thay vì yêu cầu dọn dẹp sau.
Nếu bạn muốn trở nên tốt hơn trong việc viết lời nhắc tạo ra mã an toàn hơn từ đầu, trình tối ưu hóa lời nhắc miễn phí của chúng tôi có thể giúp bạn cấu trúc các hướng dẫn của mình. Và để có hướng dẫn bảo mật đầy đủ, hãy xem hướng dẫn từng bước của chúng tôi: Cách bảo mật một ứng dụng Vibe-Coded trước khi trao cho khách hàng.
Đây là những gì chúng tôi làm mỗi tuần. Một bài phân tích sâu về các công cụ AI, quy trình làm việc và những quan điểm trung thực — không có hype, không có lót. Tham gia chúng tôi →
Tiết lộ: Một số liên kết trong bài viết này là liên kết liên kết. Chúng tôi chỉ đề xuất các công cụ mà chúng tôi đã kiểm tra cá nhân và sử dụng thường xuyên. Xem chính sách tiết lộ đầy đủ của chúng tôi.