# Vulnerable: Django views using eval() with user input
from django.http import JsonResponse
from django.views import View
from django.shortcuts import render
# Extremely dangerous: eval() with user input
class CalculatorView(View):
def get(self, request):
expression = request.GET.get('expr', '')
try:
# CRITICAL VULNERABILITY: eval() with user input
result = eval(expression)
return JsonResponse({'result': result})
except Exception as e:
return JsonResponse({'error': str(e)})
# Another dangerous pattern
def dynamic_filter(request):
model_name = request.GET.get('model', 'MyModel')
filter_expr = request.GET.get('filter', '')
# Dangerous: Dynamic code execution
code = f"from myapp.models import {model_name}"
exec(code)
# Even more dangerous: eval with user filter
filter_code = f"{model_name}.objects.filter({filter_expr})"
try:
result = eval(filter_code)
return JsonResponse({'count': result.count()})
except Exception as e:
return JsonResponse({'error': str(e)})
# Template processing vulnerability
def process_user_template(request):
template_code = request.POST.get('template', '')
context_data = request.POST.get('context', '{}')
try:
# Dangerous: eval() for context
context = eval(context_data)
# Dangerous: eval() for template processing
processed = eval(f"f'{template_code}'", context)
return JsonResponse({'rendered': processed})
except Exception as e:
return JsonResponse({'error': str(e)})
# Configuration processing
def update_config(request):
if request.method == 'POST':
config_updates = request.POST.get('config', '')
try:
# Dangerous: eval() for configuration
new_config = eval(config_updates)
# Apply configuration
for key, value in new_config.items():
setattr(settings, key, value)
return JsonResponse({'status': 'config_updated'})
except Exception as e:
return JsonResponse({'error': str(e)})
# Data transformation
def transform_data(request):
data = request.POST.get('data', '[]')
transform_func = request.POST.get('transform', 'lambda x: x')
try:
# Dangerous: eval() for data and transformation
data_list = eval(data)
transform = eval(transform_func)
result = [transform(item) for item in data_list]
return JsonResponse({'transformed': result})
except Exception as e:
return JsonResponse({'error': str(e)})
# Secure: Safe alternatives to eval() in Django
from django.http import JsonResponse
from django.views import View
from django.shortcuts import render
from django.core.exceptions import ValidationError
import ast
import operator
import re
import json
# Safe: Mathematical expression evaluation
class SafeCalculatorView(View):
def get(self, request):
expression = request.GET.get('expr', '')
# Validate expression format
if not self.is_safe_expression(expression):
return JsonResponse({'error': 'Invalid expression format'}, status=400)
try:
result = self.safe_eval(expression)
return JsonResponse({'result': result})
except (ValueError, ZeroDivisionError) as e:
return JsonResponse({'error': 'Calculation error'}, status=400)
def is_safe_expression(self, expr):
# Only allow safe mathematical characters
if not re.match(r'^[0-9+\-*/().\s]+$', expr):
return False
# Limit length
if len(expr) > 100:
return False
return True
def safe_eval(self, expression):
# Define allowed operations
allowed_ops = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.USub: operator.neg,
ast.UAdd: operator.pos
}
def eval_node(node):
if isinstance(node, ast.Constant): # Numbers
return node.value
elif isinstance(node, ast.Num): # Python < 3.8
return node.n
elif isinstance(node, ast.BinOp):
left = eval_node(node.left)
right = eval_node(node.right)
op = allowed_ops.get(type(node.op))
if op is None:
raise ValueError('Unsupported operation')
return op(left, right)
elif isinstance(node, ast.UnaryOp):
operand = eval_node(node.operand)
op = allowed_ops.get(type(node.op))
if op is None:
raise ValueError('Unsupported operation')
return op(operand)
else:
raise ValueError('Unsupported expression')
try:
tree = ast.parse(expression, mode='eval')
return eval_node(tree.body)
except (SyntaxError, ValueError) as e:
raise ValueError('Invalid expression')
# Safe: Model filtering with allowlists
def safe_dynamic_filter(request):
model_name = request.GET.get('model', '')
filter_field = request.GET.get('field', '')
filter_value = request.GET.get('value', '')
# Use allowlists for models and fields
allowed_models = {
'user': User,
'post': Post,
'comment': Comment
}
allowed_fields = {
'user': ['username', 'email', 'is_active'],
'post': ['title', 'status', 'created_date'],
'comment': ['content', 'approved']
}
if model_name not in allowed_models:
return JsonResponse({'error': 'Model not allowed'}, status=400)
if filter_field not in allowed_fields.get(model_name, []):
return JsonResponse({'error': 'Field not allowed'}, status=400)
try:
model_class = allowed_models[model_name]
# Safe: Use Django ORM with validated parameters
filter_kwargs = {filter_field: filter_value}
queryset = model_class.objects.filter(**filter_kwargs)
return JsonResponse({'count': queryset.count()})
except Exception as e:
return JsonResponse({'error': 'Filter failed'}, status=400)
# Safe: Template processing
def safe_process_user_template(request):
template_name = request.POST.get('template', '')
context_data = request.POST.get('context', '{}')
# Use allowlist for templates
allowed_templates = [
'user_welcome.html',
'order_confirmation.html',
'newsletter.html'
]
if template_name not in allowed_templates:
return JsonResponse({'error': 'Template not allowed'}, status=400)
try:
# Safe: JSON deserialization
context = json.loads(context_data)
# Validate context structure
validated_context = validate_template_context(context)
# Safe: Use Django template system
from django.template.loader import render_to_string
rendered = render_to_string(template_name, validated_context)
return JsonResponse({'rendered': rendered})
except (json.JSONDecodeError, ValidationError) as e:
return JsonResponse({'error': 'Invalid context data'}, status=400)
def validate_template_context(context):
if not isinstance(context, dict):
raise ValidationError('Context must be a dictionary')
allowed_keys = {'user_name', 'order_id', 'amount', 'date', 'items'}
validated = {}
for key, value in context.items():
if key in allowed_keys:
# Type validation and sanitization
if key == 'user_name' and isinstance(value, str):
validated[key] = value[:50] # Limit length
elif key == 'order_id' and isinstance(value, (str, int)):
validated[key] = str(value)
elif key == 'amount' and isinstance(value, (int, float)):
validated[key] = float(value)
elif key == 'date' and isinstance(value, str):
# Validate date format
from datetime import datetime
try:
datetime.strptime(value, '%Y-%m-%d')
validated[key] = value
except ValueError:
pass # Skip invalid dates
elif key == 'items' and isinstance(value, list):
validated[key] = value[:10] # Limit items
return validated
# Safe: Configuration updates
def safe_update_config(request):
if request.method == 'POST':
try:
# Safe: JSON deserialization
config_updates = json.loads(request.body)
# Validate updates
validated_updates = validate_config_updates(config_updates)
# Apply validated configuration
apply_config_updates(validated_updates)
return JsonResponse({'status': 'config_updated'})
except (json.JSONDecodeError, ValidationError) as e:
return JsonResponse({'error': 'Invalid configuration'}, status=400)
def validate_config_updates(updates):
if not isinstance(updates, dict):
raise ValidationError('Configuration must be a dictionary')
allowed_configs = {
'debug': bool,
'page_size': int,
'timeout': int,
'feature_flags': dict
}
validated = {}
for key, value in updates.items():
if key in allowed_configs:
expected_type = allowed_configs[key]
if isinstance(value, expected_type):
# Additional validation
if key == 'page_size' and 1 <= value <= 100:
validated[key] = value
elif key == 'timeout' and 1 <= value <= 300:
validated[key] = value
elif key == 'debug' and isinstance(value, bool):
validated[key] = value
elif key == 'feature_flags' and isinstance(value, dict):
# Validate feature flags
validated[key] = {k: bool(v) for k, v in value.items()
if isinstance(k, str) and len(k) <= 50}
return validated
# Safe: Data transformation
def safe_transform_data(request):
try:
# Safe: JSON deserialization
data = json.loads(request.POST.get('data', '[]'))
transform_type = request.POST.get('transform', '')
# Use predefined transformations
allowed_transforms = {
'uppercase': lambda x: x.upper() if isinstance(x, str) else x,
'lowercase': lambda x: x.lower() if isinstance(x, str) else x,
'double': lambda x: x * 2 if isinstance(x, (int, float)) else x,
'truncate': lambda x: x[:10] if isinstance(x, str) else x
}
if transform_type not in allowed_transforms:
return JsonResponse({'error': 'Transform not allowed'}, status=400)
if not isinstance(data, list) or len(data) > 1000:
return JsonResponse({'error': 'Invalid data format or too large'}, status=400)
transform_func = allowed_transforms[transform_type]
result = [transform_func(item) for item in data]
return JsonResponse({'transformed': result})
except (json.JSONDecodeError, TypeError) as e:
return JsonResponse({'error': 'Data transformation failed'}, status=400)