forked from prowler-cloud/prowler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsecurity_patterns.py
More file actions
159 lines (112 loc) · 5.35 KB
/
security_patterns.py
File metadata and controls
159 lines (112 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Example: DRF API Security Patterns
# Reference for django-drf skill
import re
from rest_framework import serializers, status, viewsets
from rest_framework.exceptions import NotFound
from rest_framework.permissions import SAFE_METHODS, BasePermission, IsAuthenticated
from rest_framework.throttling import UserRateThrottle
# =============================================================================
# INPUT VALIDATION
# =============================================================================
class ProviderCreateSerializer(serializers.Serializer):
"""Example: Input validation in serializers."""
uid = serializers.CharField(max_length=255)
provider = serializers.CharField()
def validate_uid(self, value):
"""Field-level validation with sanitization."""
# Sanitize: strip whitespace, normalize
value = value.strip().lower()
# Validate format
if not re.match(r"^[a-z0-9-]+$", value):
raise serializers.ValidationError(
"UID must be alphanumeric with hyphens only"
)
return value
def validate(self, attrs):
"""Cross-field validation."""
if attrs.get("provider") == "aws" and len(attrs.get("uid", "")) != 12:
raise serializers.ValidationError(
{"uid": "AWS account ID must be 12 digits"}
)
return attrs
# =============================================================================
# PREVENT MASS ASSIGNMENT
# =============================================================================
class UserUpdateSerializer(serializers.ModelSerializer):
"""Example: Explicit field whitelist prevents mass assignment."""
class Meta:
# GOOD: Explicit whitelist
fields = ["name", "email"]
# BAD: fields = "__all__" # Exposes is_staff, is_superuser
# BAD: exclude = ["password"] # New fields auto-exposed
class ProviderSerializer(serializers.ModelSerializer):
"""Example: Read-only fields for computed/system values."""
class Meta:
fields = ["id", "uid", "alias", "connected", "inserted_at"]
# Cannot be set via API - only read
read_only_fields = ["id", "connected", "inserted_at"]
# =============================================================================
# OBJECT-LEVEL PERMISSIONS
# =============================================================================
class IsOwnerOrReadOnly(BasePermission):
"""Example: Object-level permission check."""
def has_object_permission(self, request, view, obj):
# Read permissions for any authenticated request
if request.method in SAFE_METHODS:
return True
# Write permissions only for owner
return obj.owner == request.user
class DocumentViewSet(viewsets.ModelViewSet):
"""Example: ViewSet with object-level permissions."""
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
# =============================================================================
# RATE LIMITING (THROTTLING)
# =============================================================================
# In settings.py:
# REST_FRAMEWORK = {
# "DEFAULT_THROTTLE_CLASSES": [
# "rest_framework.throttling.AnonRateThrottle",
# "rest_framework.throttling.UserRateThrottle",
# ],
# "DEFAULT_THROTTLE_RATES": {
# "anon": "100/hour",
# "user": "1000/hour",
# },
# }
class BurstRateThrottle(UserRateThrottle):
"""Example: Custom throttle for sensitive endpoints."""
rate = "10/minute"
class PasswordResetViewSet(viewsets.ViewSet):
"""Example: Per-view throttling for sensitive endpoints."""
throttle_classes = [BurstRateThrottle]
# =============================================================================
# PREVENT INFORMATION DISCLOSURE
# =============================================================================
class SecureViewSet(viewsets.ModelViewSet):
"""Example: Prevent information disclosure patterns."""
def get_object(self):
try:
return super().get_object()
except Exception:
# GOOD: Generic message - doesn't leak internal IDs or tenant info
raise NotFound("Resource not found")
# BAD: raise NotFound(f"Provider {pk} not found in tenant {tenant_id}")
def get_queryset(self):
# Use 404 not 403 for unauthorized access (prevents enumeration)
# Filter by tenant - unauthorized users get 404, not 403
return self.queryset.filter(tenant_id=self.request.tenant_id)
# =============================================================================
# SQL INJECTION PREVENTION
# =============================================================================
def safe_query_examples(user_input):
"""Example: SQL injection prevention patterns."""
from django.db import connection
# GOOD: Parameterized via ORM
# Provider.objects.filter(uid=user_input)
# Provider.objects.extra(where=["uid = %s"], params=[user_input])
# GOOD: If raw SQL unavoidable, use parameterized queries
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM providers WHERE uid = %s", [user_input])
# BAD: String interpolation = SQL injection vulnerability
# Provider.objects.raw(f"SELECT * FROM providers WHERE uid = '{user_input}'")
# cursor.execute(f"SELECT * FROM providers WHERE uid = '{user_input}'")