eval() เป็น Built-in Function ที่ Parse และ Execute สตริงเป็น Python Code ทำให้สามารถสร้าง Dynamic Code ได้ แต่มี Security Risk ร้ายแรง หากใช้กับ Input ที่ไม่ไว้ใจได้
ไวยากรณ์
eval(expression, globals=None, locals=None)
expression: สตริงหรือ Code Object ที่จะประเมินglobals: Dictionary ของ Global Variables (Optional)locals: Dictionary ของ Local Variables (Optional)
ตัวอย่างพื้นฐาน
# คำนวณนิพจน์คณิตศาสตร์
expr = "2 + 3 * 4"
print(eval(expr)) # 14
# ใช้ Variable
x = 10
print(eval("x * 2 + 5")) # 25
# เรียกใช้ Function
print(eval("len('hello')")) # 5
print(eval("max([1,5,3])")) # 5
ตัวอย่าง Interactive Calculator
def safe_calculator():
"""Simple Calculator using eval (สำหรับ Demo เท่านั้น - ไม่ปลอดภัยสำหรับ Production)"""
print("Simple Calculator (type 'quit' to exit)")
while True:
try:
expr = input("Enter expression: ").strip()
if expr.lower() == 'quit':
break
result = eval(expr)
print(f"Result: {result}")
except Exception as e:
print(f"Error: {e}")
# safe_calculator() # Uncomment to run
⚠️ Security Risks (อันตรายมาก)
eval() รันโค้ดใดๆ ที่ส่งเข้ามา รวมถึง System Commands:
# อันตราย! หาก User Input นี้:
# "__import__('os').system('rm -rf /')"
# "__import__('os').system('cat /etc/passwd')"
# "open('secret.txt').read()"
# eval() จะ Execute จริงๆ!
วิธีป้องกัน (Mitigation Strategies)
1. Restrict Globals และ Locals (ขั้นต่ำ)
# ไม่ให้เข้าถึง Built-ins และ Globals
safe_globals = {"__builtins__": None}
safe_locals = {}
try:
eval("__import__('os').system('ls')", safe_globals, safe_locals)
except NameError as e:
print(f"Blocked: {e}") # Blocked: name '__import__' is not defined
2. Allowlist: อนุญาตเฉพาะ Functions ที่ปลอดภัย
import math
# อนุญาตเฉพาะ Math Functions
safe_dict = {
"__builtins__": None,
"abs": abs, "round": round, "min": min, "max": max, "sum": sum,
"pow": pow, "divmod": divmod,
# Math module functions
"sin": math.sin, "cos": math.cos, "tan": math.tan,
"sqrt": math.sqrt, "log": math.log, "exp": math.exp,
"pi": math.pi, "e": math.e,
}
# ทดสอบ
print(eval("sqrt(16) + sin(pi/2)", safe_dict)) # 4.0 + 1.0 = 5.0
# พยายามเข้าถึงอันตราย
try:
eval("__import__('os').system('ls')", safe_dict)
except NameError:
print("Blocked dangerous call")
3. ใช้ ast.literal_eval แทน (สำหรับ Literals เท่านั้น)
import ast
# ปลอดภัย: Parse เฉพาะ Literals (string, number, tuple, list, dict, bool, None)
print(ast.literal_eval("[1, 2, 3]")) # [1, 2, 3]
print(ast.literal_eval("{'a': 1}")) # {'a': 1}
print(ast.literal_eval("'hello'")) # 'hello'
print(ast.literal_eval("1 + 2")) # ValueError: ไม่ใช่ Literal
# ไม่สามารถ Execute Code ได้
try:
ast.literal_eval("__import__('os').system('ls')")
except ValueError as e:
print(f"Safe: {e}")
4. ใช้ Library เฉพาะทาง: simpleeval, asteval
# pip install simpleeval
from simpleeval import simple_eval
# Safe Expression Evaluator
print(simple_eval("2 + 3 * 4")) # 14
print(simple_eval("sqrt(16)")) # Error: name 'sqrt' not defined
# เพิ่ม Functions
print(simple_eval("sqrt(16)", functions={"sqrt": lambda x: x**0.5})) # 4.0
# Blocked dangerous operations
try:
simple_eval("__import__('os').system('ls')")
except Exception as e:
print(f"Blocked: {type(e).__name__}")
เมื่อไหร่ควร/ไม่ควรใช้ eval()
| สถานการณ์ | ควรใช้ eval()? | ทางเลือก |
|---|---|---|
| User Input จาก Web Form/API | ❌ ห้ามเด็ดขาด | ast.literal_eval, simpleeval, JSON |
| Config File ที่คุณควบคุมได้เต็มที่ | ⚠️ ยังเสี่ยง | YAML, JSON, TOML, ConfigParser |
| Internal Tool / Trusted Developer Only | ⚠️ ระวัง (ยังมี Bug Risk) | ast.literal_eval, Custom Parser |
| Math Expression Parser (Calculator App) | ⚠️ ถ้าจำเป็น | simpleeval, asteval, numexpr |
| Dynamic Code Generation (Plugin System) | ⚠️ Advanced Only | Importlib, Entry Points, WASM |
สรุป
eval()มีพลังมากแต่อันตราย - อย่าใช้กับ Untrusted Input- ใช้
ast.literal_eval()สำหรับ Parse Literals (Safe) - ใช้
simpleevalหรือastevalสำหรับ Expression Evaluation (Safer) - ถ้าจำเป็นต้องใช้ eval(): จำกัด
__builtins__=Noneและ Allowlist Functions เท่านั้น - Audit Code ที่ใช้ eval() อย่างสม่ำเสมอ