-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrules.py
More file actions
137 lines (118 loc) · 4.41 KB
/
Copy pathrules.py
File metadata and controls
137 lines (118 loc) · 4.41 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
# regras de seguranca pra analisar endpoints de API
CAMPOS_SENSIVEIS = {"password", "token", "secret", "cpf", "card_number"}
def _problema(endpoint, rule_id, descricao, risco, recomendacao):
# monta o dict padrao de um problema encontrado
return {
"rule_id": rule_id,
"method": endpoint.get("method", "UNKNOWN"),
"path": endpoint.get("path", "UNKNOWN"),
"descricao": descricao,
"risco": risco,
"recomendacao": recomendacao,
}
def rodar_todas_as_regras(endpoints):
# roda todas as regras e junta os resultados
regras = [
regra_sem_autenticacao,
regra_sem_object_authorization,
regra_admin_sem_role,
regra_webhook_sem_assinatura,
regra_login_sem_rate_limit,
regra_campos_sensiveis,
]
problemas = []
for regra in regras:
problemas.extend(regra(endpoints))
return problemas
def regra_sem_autenticacao(endpoints):
# detecta endpoints que nao exigem autenticacao
problemas = []
for ep in endpoints:
if not ep.get("auth_required", True):
problemas.append(_problema(
ep,
rule_id="R001",
descricao="endpoint sem autenticacao",
risco="high",
recomendacao="adicionar autenticacao (bearer token, api key, etc)",
))
return problemas
def regra_sem_object_authorization(endpoints):
# rota com {id} mas sem checar se o usuario tem acesso ao objeto
problemas = []
for ep in endpoints:
path = ep.get("path", "")
if "{id}" in path and not ep.get("object_authorization", False):
problemas.append(_problema(
ep,
rule_id="R002",
descricao="rota com {id} sem verificar se o usuario e dono do objeto",
risco="critical",
recomendacao="checar se o usuario autenticado tem permissao pra acessar esse objeto",
))
return problemas
def regra_admin_sem_role(endpoints):
# rota /admin sem exigir role especifica
problemas = []
for ep in endpoints:
path = ep.get("path", "")
if "/admin" in path and not ep.get("role_required"):
problemas.append(_problema(
ep,
rule_id="R003",
descricao="rota admin sem restricao de role",
risco="critical",
recomendacao="restringir pra usuarios com role admin",
))
return problemas
def regra_webhook_sem_assinatura(endpoints):
# webhook sem verificar assinatura
problemas = []
for ep in endpoints:
path = ep.get("path", "")
if "webhook" in path.lower() and not ep.get("signature_required", False):
problemas.append(_problema(
ep,
rule_id="R004",
descricao="webhook sem verificacao de assinatura",
risco="high",
recomendacao="implementar verificacao HMAC-SHA256 no webhook",
))
return problemas
def regra_login_sem_rate_limit(endpoints):
# login sem limite de tentativas
problemas = []
for ep in endpoints:
path = ep.get("path", "")
if "login" in path.lower() and not ep.get("rate_limit", False):
problemas.append(_problema(
ep,
rule_id="R005",
descricao="endpoint de login sem rate limit",
risco="high",
recomendacao="adicionar rate limit pra evitar brute force",
))
return problemas
def regra_campos_sensiveis(endpoints):
# campos como password, token, cpf aparecendo na definicao
problemas = []
for ep in endpoints:
campos = ep.get("sensitive_fields", [])
expostos = [c for c in campos if c.lower() in CAMPOS_SENSIVEIS]
if expostos:
problemas.append(_problema(
ep,
rule_id="R006",
descricao=f"campos sensiveis expostos: {', '.join(expostos)}",
risco="medium",
recomendacao="mascarar ou remover esses campos da resposta",
))
return problemas
def score_endpoint(endpoint):
# retorna o pior nivel de risco do endpoint
problemas = rodar_todas_as_regras([endpoint])
niveis = [p["risco"] for p in problemas]
for nivel in ["critical", "high", "medium", "low"]:
if nivel in niveis:
return nivel
return "low"