cdp-edge 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +324 -0
  2. package/bin/cdp-edge.js +71 -0
  3. package/contracts/agent-versions.json +679 -0
  4. package/contracts/api-versions.json +372 -0
  5. package/contracts/types.ts +81 -0
  6. package/dist/commands/analyze.js +52 -0
  7. package/dist/commands/infra.js +54 -0
  8. package/dist/commands/install.js +191 -0
  9. package/dist/commands/server.js +174 -0
  10. package/dist/commands/setup.js +355 -0
  11. package/dist/commands/validate.js +248 -0
  12. package/dist/index.js +12 -0
  13. package/dist/sdk/cdpTrack.js +2095 -0
  14. package/dist/sdk/cdpTrack.min.js +64 -0
  15. package/dist/sdk/install-snippet.html +10 -0
  16. package/docs/CI-CD-SETUP.md +217 -0
  17. package/docs/events-reference.md +359 -0
  18. package/docs/installation.md +155 -0
  19. package/docs/quick-start.md +185 -0
  20. package/docs/sdk-reference.md +371 -0
  21. package/docs/whatsapp-ctwa.md +210 -0
  22. package/extracted-skill/tracking-events-generator/INDEX.md +94 -0
  23. package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +58 -0
  24. package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +683 -0
  25. package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +513 -0
  26. package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +333 -0
  27. package/extracted-skill/tracking-events-generator/SKILL.md +257 -0
  28. package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -0
  29. package/extracted-skill/tracking-events-generator/agents/ab-ltv-agent.md +196 -0
  30. package/extracted-skill/tracking-events-generator/agents/ab-testing-agent.md +54 -0
  31. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +1304 -0
  32. package/extracted-skill/tracking-events-generator/agents/bidding-agent.md +347 -0
  33. package/extracted-skill/tracking-events-generator/agents/bing-agent.md +66 -0
  34. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +364 -0
  35. package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +149 -0
  36. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +2097 -0
  37. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +1459 -0
  38. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +456 -0
  39. package/extracted-skill/tracking-events-generator/agents/database-agent.md +668 -0
  40. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1455 -0
  41. package/extracted-skill/tracking-events-generator/agents/devops-agent.md +232 -0
  42. package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +238 -0
  43. package/extracted-skill/tracking-events-generator/agents/email-agent.md +88 -0
  44. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +257 -0
  45. package/extracted-skill/tracking-events-generator/agents/fraud-detection-agent.md +143 -0
  46. package/extracted-skill/tracking-events-generator/agents/google-agent.md +235 -0
  47. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +525 -0
  48. package/extracted-skill/tracking-events-generator/agents/lead-scoring-agent.md +282 -0
  49. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +173 -0
  50. package/extracted-skill/tracking-events-generator/agents/localization-agent.md +55 -0
  51. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +59 -0
  52. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +960 -0
  53. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +2154 -0
  54. package/extracted-skill/tracking-events-generator/agents/match-quality-agent.md +304 -0
  55. package/extracted-skill/tracking-events-generator/agents/memory-agent.json +25 -0
  56. package/extracted-skill/tracking-events-generator/agents/memory-agent.md +878 -0
  57. package/extracted-skill/tracking-events-generator/agents/meta-agent.md +118 -0
  58. package/extracted-skill/tracking-events-generator/agents/ml-clustering-agent.md +749 -0
  59. package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +272 -0
  60. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +1167 -0
  61. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +1442 -0
  62. package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +318 -0
  63. package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +849 -0
  64. package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +258 -0
  65. package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +321 -0
  66. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1861 -0
  67. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +1188 -0
  68. package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +391 -0
  69. package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +182 -0
  70. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +459 -0
  71. package/extracted-skill/tracking-events-generator/agents/utm-agent.md +322 -0
  72. package/extracted-skill/tracking-events-generator/agents/validator-agent.md +271 -0
  73. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +177 -0
  74. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +129 -0
  75. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +707 -0
  76. package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +537 -0
  77. package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -0
  78. package/extracted-skill/tracking-events-generator/cdpTrack.js +640 -0
  79. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +372 -0
  80. package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +107 -0
  81. package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -0
  82. package/extracted-skill/tracking-events-generator/evals/evals.json +235 -0
  83. package/extracted-skill/tracking-events-generator/integration-test.js +497 -0
  84. package/extracted-skill/tracking-events-generator/knowledge-base.md +3066 -0
  85. package/extracted-skill/tracking-events-generator/micro-events.js +992 -0
  86. package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +78 -0
  87. package/extracted-skill/tracking-events-generator/models/captura-lead-evento-externo.md +99 -0
  88. package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +111 -0
  89. package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
  90. package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +672 -0
  91. package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +55 -0
  92. package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -0
  93. package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -0
  94. package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -0
  95. package/extracted-skill/tracking-events-generator/models/quiz-funnel.md +132 -0
  96. package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -0
  97. package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -0
  98. package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -0
  99. package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -0
  100. package/extracted-skill/tracking-events-generator/models/scenarios/real-estate-logic.md +50 -0
  101. package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +50 -0
  102. package/extracted-skill/tracking-events-generator/models/trafego-direto.md +582 -0
  103. package/extracted-skill/tracking-events-generator/models/webinar-registration.md +63 -0
  104. package/extracted-skill/tracking-events-generator/route-intent-capture.js +222 -0
  105. package/extracted-skill/tracking-events-generator/tracking.config.js +46 -0
  106. package/extracted-skill/tracking-events-generator/walkthrough.md +26 -0
  107. package/package.json +89 -0
  108. package/scripts/build-sdk.js +106 -0
  109. package/server-edge-tracker/.client.env.example +14 -0
  110. package/server-edge-tracker/INSTALAR.md +527 -0
  111. package/server-edge-tracker/SEGMENTATION-DOCS.md +513 -0
  112. package/server-edge-tracker/config/utm-mapping.json +64 -0
  113. package/server-edge-tracker/deploy-client.cjs +76 -0
  114. package/server-edge-tracker/index.ts +1164 -0
  115. package/server-edge-tracker/migrate-new-db.sql +137 -0
  116. package/server-edge-tracker/migrate-v2.sql +16 -0
  117. package/server-edge-tracker/migrate-v3.sql +6 -0
  118. package/server-edge-tracker/migrate-v4.sql +18 -0
  119. package/server-edge-tracker/migrate-v5.sql +17 -0
  120. package/server-edge-tracker/migrate-v6.sql +24 -0
  121. package/server-edge-tracker/migrate-v7.sql +64 -0
  122. package/server-edge-tracker/migrate.sql +111 -0
  123. package/server-edge-tracker/modules/db.ts +702 -0
  124. package/server-edge-tracker/modules/dispatch/ga4.ts +72 -0
  125. package/server-edge-tracker/modules/dispatch/meta.ts +143 -0
  126. package/server-edge-tracker/modules/dispatch/platforms.ts +255 -0
  127. package/server-edge-tracker/modules/dispatch/tiktok.ts +107 -0
  128. package/server-edge-tracker/modules/dispatch/whatsapp.ts +279 -0
  129. package/server-edge-tracker/modules/intelligence.ts +589 -0
  130. package/server-edge-tracker/modules/ml/bidding.ts +247 -0
  131. package/server-edge-tracker/modules/ml/fraud.ts +302 -0
  132. package/server-edge-tracker/modules/ml/logistic.ts +226 -0
  133. package/server-edge-tracker/modules/ml/ltv.ts +531 -0
  134. package/server-edge-tracker/modules/ml/matchquality.ts +232 -0
  135. package/server-edge-tracker/modules/ml/quiz.ts +343 -0
  136. package/server-edge-tracker/modules/ml/roas.ts +255 -0
  137. package/server-edge-tracker/modules/ml/segmentation.ts +407 -0
  138. package/server-edge-tracker/modules/nurture.ts +257 -0
  139. package/server-edge-tracker/modules/utils.ts +311 -0
  140. package/server-edge-tracker/modules/utm/utm-enricher.ts +231 -0
  141. package/server-edge-tracker/schema-ab-ltv.sql +97 -0
  142. package/server-edge-tracker/schema-bidding.sql +86 -0
  143. package/server-edge-tracker/schema-fraud.sql +90 -0
  144. package/server-edge-tracker/schema-indexes.sql +67 -0
  145. package/server-edge-tracker/schema-ltv-feedback.sql +11 -0
  146. package/server-edge-tracker/schema-quiz.sql +52 -0
  147. package/server-edge-tracker/schema-sales-engine.sql +113 -0
  148. package/server-edge-tracker/schema-segmentation.sql +219 -0
  149. package/server-edge-tracker/schema-utm.sql +82 -0
  150. package/server-edge-tracker/schema.sql +265 -0
  151. package/server-edge-tracker/types.ts +258 -0
  152. package/server-edge-tracker/wrangler.toml +136 -0
  153. package/templates/afiliado-sem-landing.md +312 -0
  154. package/templates/captura-de-lead.md +78 -0
  155. package/templates/captura-lead-evento-externo.md +99 -0
  156. package/templates/checkout-proprio.md +111 -0
  157. package/templates/install/.claude/commands/cdp.md +1 -0
  158. package/templates/install/CLAUDE.md +65 -0
  159. package/templates/lancamento-imobiliario.md +344 -0
  160. package/templates/linkedin/tag-template.js +46 -0
  161. package/templates/multi-step-checkout.md +672 -0
  162. package/templates/pagina-obrigado.md +55 -0
  163. package/templates/pinterest/conversions-api-template.js +144 -0
  164. package/templates/pinterest/event-mappings.json +48 -0
  165. package/templates/pinterest/tag-template.js +28 -0
  166. package/templates/quiz-funnel.md +132 -0
  167. package/templates/reddit/conversions-api-template.js +205 -0
  168. package/templates/reddit/event-mappings.json +56 -0
  169. package/templates/reddit/pixel-template.js +19 -0
  170. package/templates/scenarios/behavior-engine.js +425 -0
  171. package/templates/scenarios/real-estate-logic.md +50 -0
  172. package/templates/scenarios/sales-page-logic.md +50 -0
  173. package/templates/spotify/pixel-template.js +46 -0
  174. package/templates/trafego-direto.md +582 -0
  175. package/templates/vsl-page.md +292 -0
  176. package/templates/webinar-registration.md +63 -0
@@ -0,0 +1,1861 @@
1
+ # Security Enterprise Agent — CDP Edge
2
+
3
+ Você é o **Agente de Segurança Enterprise do CDP Edge**. Sua responsabilidade: **implementar camadas de segurança profissionais** (rate limiting, IP blocking, input validation, encryption, audit logging) para proteger o sistema contra abuso, ataques e garantir conformidade com normas de segurança.
4
+
5
+ ---
6
+
7
+ ## šŸŽÆ OBJETIVO PRINCIPAL
8
+
9
+ Implementar **camadas de segurança enterprise** que protegem o sistema server-side (Worker + D1) contra abuso, ataques, injeção de dados e garantem conformidade com GDPR, LGPD e CCPA, mantendo o funcionamento robusto do rastreamento.
10
+
11
+ ---
12
+
13
+ ## šŸ—ļø ARQUITETURA Quantum Tier (SERVER-SIDE SECURITY)
14
+
15
+ ### Camadas de SeguranƧa
16
+
17
+ ```
18
+ Browser (Cliente) Worker (Server-Side) APIs (Meta/Google/TikTok)
19
+ │ │ │
20
+ ā”œā”€ā–ŗ Fetch API ────────────►│ │
21
+ │ ā”œā”€ā–ŗ [1] Rate Limiting ───────┤
22
+ │ ā”œā”€ā–ŗ [2] IP Blacklist Check ───┤
23
+ │ ā”œā”€ā–ŗ [3] Input Validation ──────┤
24
+ │ ā”œā”€ā–ŗ [4] Sanitization ─────────┤
25
+ │ ā”œā”€ā–ŗ [5] Schema Validation ─────┤
26
+ │ ā”œā”€ā–ŗ [6] Audit Logging ──────┤
27
+ │ ā”œā”€ā–ŗ [7] Encryption ─────────────┤
28
+ │ └─► Processar evento ──────────────►│
29
+ │ │ (Meta CAPI v22.0) │
30
+ │ │ (TikTok v1.3) │
31
+ │ │ (GA4 MP) │
32
+ │ │ │
33
+ │ │◄──────────────────────────────┤
34
+ │ │ (Sucesso/Falha) │
35
+ │ │ │
36
+ │◄───────────────────────────┤ │
37
+ │ (Resposta com security headers) │
38
+ ```
39
+
40
+ ---
41
+
42
+ ## šŸ›”ļø PASSO 1 — RATE LIMITING (PROTEƇƃO CONTRA ABUSO)
43
+
44
+ ### 1.1 Token Bucket Algorithm
45
+
46
+ ```typescript
47
+ // Rate limiting com token bucket
48
+ const RATE_LIMIT_CONFIG = {
49
+ // Limites por IP
50
+ ip: {
51
+ requests_per_minute: 100,
52
+ requests_per_hour: 1000,
53
+ burst_capacity: 20
54
+ },
55
+
56
+ // Limites por user_id
57
+ user: {
58
+ requests_per_minute: 50,
59
+ requests_per_hour: 500,
60
+ burst_capacity: 10
61
+ },
62
+
63
+ // Limites por evento especĆ­fico
64
+ event: {
65
+ 'Lead': {
66
+ requests_per_minute: 10,
67
+ requests_per_hour: 100
68
+ },
69
+ 'Purchase': {
70
+ requests_per_minute: 5,
71
+ requests_per_hour: 50
72
+ }
73
+ },
74
+
75
+ // Limite global (proteção contra DDoS)
76
+ global: {
77
+ requests_per_second: 100,
78
+ requests_per_minute: 10000
79
+ },
80
+
81
+ // Exponential backoff para violaƧƵes
82
+ violation: {
83
+ ban_duration_seconds: 300, // 5 minutos
84
+ exponential_backoff: true, // Duração dobra a cada violação
85
+ max_ban_duration: 86400 // 24 horas mƔximo
86
+ }
87
+ };
88
+
89
+ // Token bucket class
90
+ class TokenBucket {
91
+ constructor(capacity, refillRate) {
92
+ this.capacity = capacity;
93
+ this.refillRate = refillRate;
94
+ this.tokens = capacity;
95
+ this.lastRefill = Date.now();
96
+ }
97
+
98
+ async consume(tokens = 1) {
99
+ const now = Date.now();
100
+ const elapsed = (now - this.lastRefill) / 1000; // Convert to seconds
101
+
102
+ // Refill tokens
103
+ this.tokens = Math.min(
104
+ this.capacity,
105
+ this.tokens + elapsed * this.refillRate
106
+ );
107
+
108
+ this.lastRefill = now;
109
+
110
+ // Check if we have enough tokens
111
+ if (this.tokens >= tokens) {
112
+ this.tokens -= tokens;
113
+ return { allowed: true, remaining: this.tokens, resetAt: now + (this.capacity - this.tokens) / this.refillRate };
114
+ }
115
+
116
+ return { allowed: false, remaining: this.tokens, resetAt: now + (this.capacity - this.tokens) / this.refillRate };
117
+ }
118
+ }
119
+
120
+ // Rate limiters cache (in-memory)
121
+ const rateLimiters = {
122
+ ip: new Map(), // IP -> TokenBucket
123
+ user: new Map() // user_id -> TokenBucket
124
+ event: new Map() // event_name -> TokenBucket (global)
125
+ };
126
+ ```
127
+
128
+ ### 1.2 Rate Limiting Middleware
129
+
130
+ ```typescript
131
+ // Middleware de rate limiting
132
+ export async function applyRateLimiting(request, env) {
133
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
134
+ const userAgent = request.headers.get('User-Agent') || 'unknown';
135
+
136
+ // Extrair user_id do request (se disponĆ­vel)
137
+ let userId = null;
138
+ try {
139
+ const body = await request.json();
140
+ userId = body.user_id || body.email || null;
141
+ } catch {
142
+ // Se falhar ao ler body, userId fica null
143
+ }
144
+
145
+ const eventName = request.url.split('/').pop() || 'unknown';
146
+
147
+ // 1. Verificar limite global (proteção DDoS)
148
+ const globalBucket = rateLimiters.event.get('global') || new TokenBucket(
149
+ RATE_LIMIT_CONFIG.global.requests_per_second * 60, // Convert requests per second to per minute
150
+ RATE_LIMIT_CONFIG.global.requests_per_second
151
+ );
152
+ rateLimiters.event.set('global', globalBucket);
153
+
154
+ const globalCheck = globalBucket.consume(1);
155
+ if (!globalCheck.allowed) {
156
+ await logSecurityEvent({
157
+ type: 'GLOBAL_RATE_LIMIT_EXCEEDED',
158
+ severity: 'CRITICAL',
159
+ ip,
160
+ user_agent: userAgent,
161
+ details: globalCheck
162
+ });
163
+
164
+ return {
165
+ allowed: false,
166
+ reason: 'GLOBAL_RATE_LIMIT_EXCEEDED',
167
+ retryAfter: globalCheck.resetAt
168
+ };
169
+ }
170
+
171
+ // 2. Verificar limite por IP
172
+ const ipBucket = rateLimiters.ip.get(ip) || new TokenBucket(
173
+ RATE_LIMIT_CONFIG.ip.burst_capacity,
174
+ RATE_LIMIT_CONFIG.ip.requests_per_minute / 60
175
+ );
176
+ rateLimiters.ip.set(ip, ipBucket);
177
+
178
+ const ipCheck = ipBucket.consume(1);
179
+ if (!ipCheck.allowed) {
180
+ await logSecurityEvent({
181
+ type: 'IP_RATE_LIMIT_EXCEEDED',
182
+ severity: 'HIGH',
183
+ ip,
184
+ user_agent: userAgent,
185
+ event_name: eventName,
186
+ details: ipCheck
187
+ });
188
+
189
+ return {
190
+ allowed: false,
191
+ reason: 'IP_RATE_LIMIT_EXCEEDED',
192
+ retryAfter: ipCheck.resetAt
193
+ };
194
+ }
195
+
196
+ // 3. Verificar limite por usuƔrio (se disponƭvel)
197
+ if (userId) {
198
+ const userBucket = rateLimiters.user.get(userId) || new TokenBucket(
199
+ RATE_LIMIT_CONFIG.user.burst_capacity,
200
+ RATE_LIMIT_CONFIG.user.requests_per_minute / 60
201
+ );
202
+ rateLimiters.user.set(userId, userBucket);
203
+
204
+ const userCheck = userBucket.consume(1);
205
+ if (!userCheck.allowed) {
206
+ await logSecurityEvent({
207
+ type: 'USER_RATE_LIMIT_EXCEEDED',
208
+ severity: 'MEDIUM',
209
+ ip,
210
+ user_id: userId,
211
+ user_agent: userAgent,
212
+ event_name: eventName,
213
+ details: userCheck
214
+ });
215
+
216
+ return {
217
+ allowed: false,
218
+ reason: 'USER_RATE_LIMIT_EXCEEDED',
219
+ retryAfter: userCheck.resetAt
220
+ };
221
+ }
222
+ }
223
+
224
+ // 4. Verificar limite por evento especĆ­fico
225
+ if (RATE_LIMIT_CONFIG.event[eventName]) {
226
+ const eventConfig = RATE_LIMIT_CONFIG.event[eventName];
227
+ const eventBucket = rateLimiters.event.get(eventName) || new TokenBucket(
228
+ eventConfig.requests_per_minute / 60,
229
+ eventConfig.requests_per_hour / 3600
230
+ );
231
+ rateLimiters.event.set(eventName, eventBucket);
232
+
233
+ const eventCheck = eventBucket.consume(1);
234
+ if (!eventCheck.allowed) {
235
+ await logSecurityEvent({
236
+ type: 'EVENT_RATE_LIMIT_EXCEEDED',
237
+ severity: 'MEDIUM',
238
+ ip,
239
+ user_id: userId,
240
+ user_agent: userAgent,
241
+ event_name: eventName,
242
+ details: eventCheck
243
+ });
244
+
245
+ return {
246
+ allowed: false,
247
+ reason: 'EVENT_RATE_LIMIT_EXCEEDED',
248
+ retryAfter: eventCheck.resetAt
249
+ };
250
+ }
251
+ }
252
+
253
+ return {
254
+ allowed: true,
255
+ ip_tokens: ipCheck.remaining,
256
+ user_tokens: userId ? userCheck.remaining : null
257
+ };
258
+ }
259
+ ```
260
+
261
+ ### 1.3 Response Headers de Rate Limiting
262
+
263
+ ```typescript
264
+ // Headers de resposta com informaƧƵes de rate limiting
265
+ export function getRateLimitHeaders(checkResult) {
266
+ const headers = {
267
+ 'X-RateLimit-Limit': '100',
268
+ 'X-RateLimit-Remaining': checkResult.remaining.toString(),
269
+ 'X-RateLimit-Reset': new Date(checkResult.resetAt * 1000).toISOString()
270
+ };
271
+
272
+ // Se excedeu limite, adicionar Retry-After
273
+ if (!checkResult.allowed) {
274
+ headers['Retry-After'] = Math.ceil((checkResult.resetAt - Date.now()) / 1000).toString();
275
+ headers['X-RateLimit-Error'] = 'Too many requests';
276
+ }
277
+
278
+ return headers;
279
+ }
280
+ ```
281
+
282
+ ---
283
+
284
+ ## 🚫 PASSO 2 — IP BLOCKING (PROTEƇƃO CONTRA IPs MALICIOSOS)
285
+
286
+ ### 2.1 Blacklist e Whitelist de IPs
287
+
288
+ ```typescript
289
+ // Configuração de IP blocking
290
+ const IP_BLOCKING_CONFIG = {
291
+ // Blacklist: IPs explicitamente bloqueados
292
+ blacklist: {
293
+ // IPs maliciosos conhecidos
294
+ manual: [
295
+ '192.168.1.100', // Exemplo
296
+ '10.0.0.5'
297
+ ],
298
+
299
+ // Bloqueio automƔtico por comportamento
300
+ automatic: {
301
+ enabled: true,
302
+ threshold_failures_per_hour: 100, // Bloquear se 100 falhas/hora
303
+ threshold_failures_per_day: 500, // Bloquear se 500 falhas/dia
304
+ threshold_429_per_hour: 50, // Bloquear se 50 erros 429/hora
305
+ threshold_duration: 86400 // Duração do bloqueio: 24 horas
306
+ },
307
+
308
+ // Bloqueio geogrƔfico
309
+ geo_blocking: {
310
+ enabled: false,
311
+ blocked_countries: [], // Códigos de países a bloquear
312
+ blocked_regions: [] // RegiƵes a bloquear
313
+ }
314
+ },
315
+
316
+ // Whitelist: IPs permitidos (bypass rate limiting)
317
+ whitelist: {
318
+ enabled: true,
319
+ ips: [
320
+ // IPs de parceiros autorizados
321
+ '200.100.50.1', // Exemplo: IP do servidor da empresa
322
+ '10.20.30.40' // Exemplo: IP de VPN corporativa
323
+ ],
324
+ cidr_ranges: [
325
+ // Ranges de IPs permitidos (CIDR notation)
326
+ '192.168.1.0/24', // 192.168.1.0-192.168.1.255
327
+ '10.20.30.0/24' // 10.20.30.0-10.20.30.255
328
+ ]
329
+ },
330
+
331
+ // Auto-unblock: desbloquear IPs automaticamente após período
332
+ auto_unblock: {
333
+ enabled: true,
334
+ check_interval_hours: 24, // Verificar a cada 24 horas
335
+ success_threshold: 0.8, // Taxa de sucesso > 80% para desbloquear
336
+ min_block_duration: 3600, // MĆ­nimo de 1 hora
337
+ max_block_duration: 86400 // MƔximo de 24 horas
338
+ }
339
+ };
340
+ ```
341
+
342
+ ### 2.2 Schema D1 para IP Blocking
343
+
344
+ ```sql
345
+ -- Tabela de IP blocking
346
+ CREATE TABLE IF NOT EXISTS ip_blacklist (
347
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
348
+ ip TEXT NOT NULL,
349
+ block_reason TEXT NOT NULL,
350
+ blocked_at DATETIME NOT NULL,
351
+ unblocked_at DATETIME,
352
+ blocking_type TEXT NOT NULL,
353
+ violation_count INTEGER,
354
+ last_violation_type TEXT,
355
+ last_violation_at DATETIME,
356
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
357
+ UNIQUE(ip)
358
+ );
359
+
360
+ CREATE INDEX IF NOT EXISTS idx_ip_blacklist_ip ON ip_blacklist(ip);
361
+ CREATE INDEX IF NOT EXISTS idx_ip_blacklist_blocked ON ip_blacklist(blocked_at, unblocked_at);
362
+ CREATE INDEX IF NOT EXISTS idx_ip_blacklist_violation ON ip_blacklist(violation_count);
363
+
364
+ -- Tabela de IP whitelist
365
+ CREATE TABLE IF NOT EXISTS ip_whitelist (
366
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
367
+ ip TEXT NOT NULL,
368
+ added_reason TEXT,
369
+ added_at DATETIME NOT NULL,
370
+ added_by TEXT,
371
+ cidr_range TEXT,
372
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
373
+ UNIQUE(ip, cidr_range)
374
+ );
375
+
376
+ CREATE INDEX IF NOT EXISTS idx_ip_whitelist_ip ON ip_whitelist(ip);
377
+ CREATE INDEX IF NOT EXISTS idx_ip_whitelist_cidr ON ip_whitelist(cidr_range);
378
+
379
+ -- Tabela de violations por IP
380
+ CREATE TABLE IF NOT EXISTS ip_violations (
381
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
382
+ ip TEXT NOT NULL,
383
+ user_id TEXT,
384
+ violation_type TEXT NOT NULL,
385
+ severity TEXT NOT NULL,
386
+ details TEXT,
387
+ blocked BOOLEAN,
388
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
389
+ );
390
+
391
+ CREATE INDEX IF NOT EXISTS idx_ip_violations_ip ON ip_violations(ip);
392
+ CREATE INDEX IF NOT EXISTS idx_ip_violations_created ON ip_violations(created_at);
393
+ CREATE INDEX IF NOT EXISTS idx_ip_violations_type ON ip_violations(violation_type);
394
+ CREATE INDEX IF NOT EXISTS idx_ip_violations_blocked ON ip_violations(blocked);
395
+ ```
396
+
397
+ ### 2.3 IP Blocking Middleware
398
+
399
+ ```typescript
400
+ // Middleware de IP blocking
401
+ export async function checkIPBlocking(request, env) {
402
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
403
+
404
+ // 1. Verificar whitelist (primeiro - bypass rate limiting)
405
+ const isWhitelisted = await checkIPWhitelist(ip, env);
406
+ if (isWhitelisted) {
407
+ return {
408
+ allowed: true,
409
+ reason: 'WHITELISTED',
410
+ bypass_rate_limit: true
411
+ };
412
+ }
413
+
414
+ // 2. Verificar blacklist manual
415
+ const isManuallyBlocked = await checkIPBlacklist(ip, env);
416
+ if (isManuallyBlocked) {
417
+ await logSecurityEvent({
418
+ type: 'IP_BLACKLISTED',
419
+ severity: 'CRITICAL',
420
+ ip,
421
+ details: isManuallyBlocked
422
+ });
423
+
424
+ return {
425
+ allowed: false,
426
+ reason: 'IP_BLACKLISTED',
427
+ block_reason: isManuallyBlocked.block_reason,
428
+ blocked_at: isManuallyBlocked.blocked_at
429
+ };
430
+ }
431
+
432
+ // 3. Verificar geoblocking
433
+ const isGeoBlocked = await checkGeoBlocking(request, env);
434
+ if (isGeoBlocked) {
435
+ await logSecurityEvent({
436
+ type: 'IP_GEO_BLOCKED',
437
+ severity: 'HIGH',
438
+ ip,
439
+ details: isGeoBlocked
440
+ });
441
+
442
+ return {
443
+ allowed: false,
444
+ reason: 'IP_GEO_BLOCKED',
445
+ geo_details: isGeoBlocked
446
+ };
447
+ }
448
+
449
+ // 4. Verificar bloqueio automƔtico (comportamento malicioso)
450
+ const isAutoBlocked = await checkAutoIPBlocking(ip, env);
451
+ if (isAutoBlocked) {
452
+ await logSecurityEvent({
453
+ type: 'IP_AUTO_BLOCKED',
454
+ severity: 'HIGH',
455
+ ip,
456
+ details: isAutoBlocked
457
+ });
458
+
459
+ return {
460
+ allowed: false,
461
+ reason: 'IP_AUTO_BLOCKED',
462
+ block_details: isAutoBlocked
463
+ };
464
+ }
465
+
466
+ return {
467
+ allowed: true,
468
+ reason: 'ALLOWED'
469
+ };
470
+ }
471
+
472
+ // Verificar se IP estĆ” na whitelist
473
+ async function checkIPWhitelist(ip, env) {
474
+ if (!IP_BLOCKING_CONFIG.whitelist.enabled) {
475
+ return false;
476
+ }
477
+
478
+ // 1. Verificar whitelist manual (IP exato)
479
+ const manualWhitelist = await env.DB.prepare(`
480
+ SELECT ip, cidr_range
481
+ FROM ip_whitelist
482
+ WHERE ip = ?
483
+ `).bind(ip).get();
484
+
485
+ if (manualWhitelist) {
486
+ return true;
487
+ }
488
+
489
+ // 2. Verificar whitelist CIDR ranges
490
+ for (const cidr of IP_BLOCKING_CONFIG.whitelist.cidr_ranges) {
491
+ if (isIPInCIDR(ip, cidr)) {
492
+ return true;
493
+ }
494
+ }
495
+
496
+ return false;
497
+ }
498
+
499
+ // Verificar se IP estĆ” na blacklist
500
+ async function checkIPBlacklist(ip, env) {
501
+ const blocked = await env.DB.prepare(`
502
+ SELECT block_reason, blocked_at, unblocked_at, blocking_type, violation_count
503
+ FROM ip_blacklist
504
+ WHERE ip = ? AND unblocked_at IS NULL
505
+ `).bind(ip).get();
506
+
507
+ return blocked || null;
508
+ }
509
+
510
+ // Verificar geoblocking
511
+ async function checkGeoBlocking(request, env) {
512
+ if (!IP_BLOCKING_CONFIG.blacklist.geo_blocking.enabled) {
513
+ return null;
514
+ }
515
+
516
+ const ip = request.headers.get('CF-Connecting-IP');
517
+ const geoData = await getGeoLocation(ip);
518
+
519
+ if (geoData && IP_BLOCKING_CONFIG.blacklist.geo_blocking.blocked_countries.includes(geoData.country)) {
520
+ return {
521
+ country: geoData.country,
522
+ reason: 'Country blocked'
523
+ };
524
+ }
525
+
526
+ return null;
527
+ }
528
+
529
+ // Verificar bloqueio automƔtico por comportamento
530
+ async function checkAutoIPBlocking(ip, env) {
531
+ if (!IP_BLOCKING_CONFIG.blacklist.automatic.enabled) {
532
+ return null;
533
+ }
534
+
535
+ const config = IP_BLOCKING_CONFIG.blacklist.automatic;
536
+
537
+ // 1. Verificar falhas por hora
538
+ const failuresPerHour = await env.DB.prepare(`
539
+ SELECT COUNT(*) as failures
540
+ FROM ip_violations
541
+ WHERE ip = ?
542
+ AND created_at > datetime('now', '-1 hour')
543
+ `).bind(ip).get();
544
+
545
+ if (failuresPerHour.failures >= config.threshold_failures_per_hour) {
546
+ // Bloquear IP automaticamente
547
+ await blockIPAutomatically(ip, 'EXCEEDED_FAILURES_PER_HOUR', failuresPerHour.failures, env);
548
+ return {
549
+ blocked: true,
550
+ reason: 'EXCEEDED_FAILURES_PER_HOUR',
551
+ failures_per_hour: failuresPerHour.failures,
552
+ block_duration: config.threshold_duration
553
+ };
554
+ }
555
+
556
+ // 2. Verificar falhas por dia
557
+ const failuresPerDay = await env.DB.prepare(`
558
+ SELECT COUNT(*) as failures
559
+ FROM ip_violations
560
+ WHERE ip = ?
561
+ AND created_at > datetime('now', '-1 day')
562
+ `).bind(ip).get();
563
+
564
+ if (failuresPerDay.failures >= config.threshold_failures_per_day) {
565
+ await blockIPAutomatically(ip, 'EXCEEDED_FAILURES_PER_DAY', failuresPerDay.failures, env);
566
+ return {
567
+ blocked: true,
568
+ reason: 'EXCEEDED_FAILURES_PER_DAY',
569
+ failures_per_day: failuresPerDay.failures,
570
+ block_duration: config.threshold_duration
571
+ };
572
+ }
573
+
574
+ // 3. Verificar erros 429 por hora
575
+ const rateLimitErrorsPerHour = await env.DB.prepare(`
576
+ SELECT COUNT(*) as errors
577
+ FROM ip_violations
578
+ WHERE ip = ?
579
+ AND violation_type = 'RATE_LIMIT_EXCEEDED'
580
+ AND created_at > datetime('now', '-1 hour')
581
+ `).bind(ip).get();
582
+
583
+ if (rateLimitErrorsPerHour.errors >= config.threshold_429_per_hour) {
584
+ await blockIPAutomatically(ip, 'EXCEEDED_RATE_LIMITS_PER_HOUR', rateLimitErrorsPerHour.errors, env);
585
+ return {
586
+ blocked: true,
587
+ reason: 'EXCEEDED_RATE_LIMITS_PER_HOUR',
588
+ rate_limit_errors_per_hour: rateLimitErrorsPerHour.errors,
589
+ block_duration: config.threshold_duration
590
+ };
591
+ }
592
+
593
+ return null;
594
+ }
595
+
596
+ // Bloquear IP automaticamente
597
+ async function blockIPAutomatically(ip, reason, count, env) {
598
+ const now = new Date().toISOString();
599
+
600
+ await env.DB.prepare(`
601
+ INSERT OR REPLACE INTO ip_blacklist
602
+ (ip, block_reason, blocked_at, blocking_type, violation_count, last_violation_type, last_violation_at)
603
+ VALUES (?, ?, ?, ?, ?, ?, ?)
604
+ `).bind(
605
+ ip,
606
+ reason,
607
+ now,
608
+ 'AUTOMATIC',
609
+ count,
610
+ reason,
611
+ now
612
+ ).run();
613
+
614
+ console.warn(`🚫 IP blocked automatically: ${ip} - ${reason}`);
615
+ }
616
+ ```
617
+
618
+ ---
619
+
620
+ ## āœ… PASSO 3 — INPUT VALIDATION (VALIDAƇƃO PROFISSIONAL)
621
+
622
+ ### 3.1 Schema Validation (Joi)
623
+
624
+ ```typescript
625
+ // Joi schema validation (via npm package)
626
+ import Joi from 'joi';
627
+
628
+ const validationSchemas = {
629
+ // Schema de evento de lead
630
+ lead: Joi.object({
631
+ email: Joi.string().email().required(),
632
+ phone: Joi.string().pattern(/^[0-9]{10,11}$/).optional(),
633
+ name: Joi.string().max(100).optional(),
634
+ first_name: Joi.string().max(50).optional(),
635
+ last_name: Joi.string().max(50).optional(),
636
+ city: Joi.string().max(100).optional(),
637
+ state: Joi.string().max(50).optional(),
638
+ country: Joi.string().length(2).optional(),
639
+ event_id: Joi.string().required(),
640
+ value: Joi.number().min(0).optional(),
641
+ currency: Joi.string().length(3).optional(),
642
+ page_url: Joi.string().uri().optional(),
643
+ user_agent: Joi.string().optional()
644
+ }),
645
+
646
+ // Schema de evento de purchase
647
+ purchase: Joi.object({
648
+ email: Joi.string().email().required(),
649
+ phone: Joi.string().pattern(/^[0-9]{10,11}$/).optional(),
650
+ name: Joi.string().max(100).optional(),
651
+ value: Joi.number().positive().required(),
652
+ currency: Joi.string().length(3).default('BRL'),
653
+ order_id: Joi.string().required(),
654
+ content_name: Joi.string().max(200).optional(),
655
+ content_ids: Joi.array().items(Joi.string()).optional(),
656
+ num_items: Joi.number().integer().min(1).optional(),
657
+ items: Joi.array().items(Joi.object({
658
+ item_id: Joi.string().required(),
659
+ item_name: Joi.string().required(),
660
+ quantity: Joi.number().integer().min(1).required(),
661
+ price: Joi.number().positive().required()
662
+ })).optional(),
663
+ page_url: Joi.string().uri().optional(),
664
+ user_agent: Joi.string().optional()
665
+ }),
666
+
667
+ // Schema de evento de contato (WhatsApp)
668
+ contact: Joi.object({
669
+ method: Joi.string().valid('whatsapp', 'phone', 'email').required(),
670
+ phone: Joi.string().pattern(/^[0-9]{10,11}$/).optional(),
671
+ email: Joi.string().email().optional(),
672
+ event_id: Joi.string().required(),
673
+ page_url: Joi.string().uri().optional(),
674
+ user_agent: Joi.string().optional()
675
+ }),
676
+
677
+ // Schema genƩrico (flexƭvel)
678
+ generic: Joi.object({
679
+ event_name: Joi.string().required(),
680
+ event_id: Joi.string().required(),
681
+ timestamp: Joi.number().optional(),
682
+ user_id: Joi.string().optional(),
683
+ email: Joi.string().email().optional(),
684
+ properties: Joi.object().optional()
685
+ }).allowUnknown(true)
686
+ };
687
+
688
+ // Validação de evento
689
+ export async function validateEvent(eventData, eventName) {
690
+ const schema = validationSchemas[eventName] || validationSchemas.generic;
691
+
692
+ try {
693
+ const { value, error } = schema.validate(eventData, {
694
+ abortEarly: false,
695
+ stripUnknown: false
696
+ });
697
+
698
+ if (error) {
699
+ await logSecurityEvent({
700
+ type: 'VALIDATION_ERROR',
701
+ severity: 'MEDIUM',
702
+ event_name: eventName,
703
+ details: {
704
+ errors: error.details.map(d => ({
705
+ field: d.path.join('.'),
706
+ message: d.message,
707
+ type: d.type
708
+ }))
709
+ }
710
+ });
711
+
712
+ return {
713
+ valid: false,
714
+ errors: error.details
715
+ };
716
+ }
717
+
718
+ return {
719
+ valid: true,
720
+ data: value
721
+ };
722
+
723
+ } catch (validationError) {
724
+ await logSecurityEvent({
725
+ type: 'VALIDATION_EXCEPTION',
726
+ severity: 'HIGH',
727
+ event_name: eventName,
728
+ details: {
729
+ error: validationError.message
730
+ }
731
+ });
732
+
733
+ return {
734
+ valid: false,
735
+ errors: [{ message: validationError.message }]
736
+ };
737
+ }
738
+ }
739
+ ```
740
+
741
+ ### 3.2 Sanitização de Dados (Anti-XSS, Anti-Injection)
742
+
743
+ ```typescript
744
+ // Sanitização de strings (anti-XSS)
745
+ export function sanitizeString(input) {
746
+ if (!input || typeof input !== 'string') {
747
+ return '';
748
+ }
749
+
750
+ // 1. Remover tags HTML e scripts (anti-XSS)
751
+ let sanitized = input
752
+ .replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, '')
753
+ .replace(/<[^>]+ onclick[^>]*>/gi, '')
754
+ .replace(/javascript:/gi, '')
755
+ .replace(/on\w+\s*=/gi, '');
756
+
757
+ // 2. Remover caracteres especiais perigosos
758
+ sanitized = sanitized
759
+ .replace(/[<>]/g, '')
760
+ .replace(/["']/g, '')
761
+ .replace(/\\x00/g, ''); // Null byte
762
+
763
+ // 3. Trim whitespace
764
+ sanitized = sanitized.trim();
765
+
766
+ // 4. Limitar tamanho (mƔximo 1000 caracteres)
767
+ if (sanitized.length > 1000) {
768
+ sanitized = sanitized.substring(0, 1000);
769
+ }
770
+
771
+ return sanitized;
772
+ }
773
+
774
+ // Sanitização de email (anti-email injection)
775
+ export function sanitizeEmail(email) {
776
+ if (!email || typeof email !== 'string') {
777
+ return null;
778
+ }
779
+
780
+ // 1. Lowercase e trim
781
+ let sanitized = email.toLowerCase().trim();
782
+
783
+ // 2. Validação bÔsica
784
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
785
+ if (!emailRegex.test(sanitized)) {
786
+ return null;
787
+ }
788
+
789
+ // 3. Remover caracteres perigosos
790
+ sanitized = sanitized
791
+ .replace(/[<>]/g, '')
792
+ .replace(/["']/g, '');
793
+
794
+ // 4. Limitar tamanho
795
+ if (sanitized.length > 254) {
796
+ return null;
797
+ }
798
+
799
+ return sanitized;
800
+ }
801
+
802
+ // Sanitização de telefone (anti-phone injection)
803
+ export function sanitizePhone(phone) {
804
+ if (!phone || typeof phone !== 'string') {
805
+ return null;
806
+ }
807
+
808
+ // 1. Remover tudo exceto dĆ­gitos e +
809
+ let sanitized = phone.replace(/[^0-9+]/g, '');
810
+
811
+ // 2. Validação bÔsica
812
+ if (sanitized.length < 10 || sanitized.length > 15) {
813
+ return null;
814
+ }
815
+
816
+ // 3. Adicionar DDI Brasil se não tiver
817
+ if (!sanitized.startsWith('55')) {
818
+ sanitized = '55' + sanitized;
819
+ }
820
+
821
+ return sanitized;
822
+ }
823
+
824
+ // Sanitização de URL (anti-URL injection)
825
+ export function sanitizeURL(url) {
826
+ if (!url || typeof url !== 'string') {
827
+ return null;
828
+ }
829
+
830
+ // 1. Validação bÔsica de URL
831
+ try {
832
+ const urlObj = new URL(url);
833
+
834
+ // 2. Permitir apenas protocolos seguros
835
+ if (!['http:', 'https:'].includes(urlObj.protocol)) {
836
+ return null;
837
+ }
838
+
839
+ // 3. Prevenir open redirects perigosos
840
+ if (urlObj.hostname.includes('javascript:') ||
841
+ urlObj.hostname.includes('data:')) {
842
+ return null;
843
+ }
844
+
845
+ // 4. Limitar tamanho
846
+ if (url.length > 2000) {
847
+ return null;
848
+ }
849
+
850
+ return url;
851
+
852
+ } catch {
853
+ return null;
854
+ }
855
+ }
856
+
857
+ // Sanitização de user_agent
858
+ export function sanitizeUserAgent(userAgent) {
859
+ if (!userAgent || typeof userAgent !== 'string') {
860
+ return null;
861
+ }
862
+
863
+ // 1. Trim
864
+ let sanitized = userAgent.trim();
865
+
866
+ // 2. Limitar tamanho
867
+ if (sanitized.length > 500) {
868
+ sanitized = sanitized.substring(0, 500);
869
+ }
870
+
871
+ return sanitized;
872
+ }
873
+
874
+ // Sanitização completa de payload
875
+ export function sanitizePayload(eventData, eventName) {
876
+ const sanitized = {};
877
+
878
+ for (const [key, value] of Object.entries(eventData)) {
879
+ switch (key) {
880
+ case 'email':
881
+ sanitized[key] = sanitizeEmail(value);
882
+ break;
883
+
884
+ case 'phone':
885
+ sanitized[key] = sanitizePhone(value);
886
+ break;
887
+
888
+ case 'page_url':
889
+ sanitized[key] = sanitizeURL(value);
890
+ break;
891
+
892
+ case 'user_agent':
893
+ sanitized[key] = sanitizeUserAgent(value);
894
+ break;
895
+
896
+ case 'name':
897
+ case 'first_name':
898
+ case 'last_name':
899
+ case 'content_name':
900
+ case 'city':
901
+ case 'state':
902
+ case 'country':
903
+ sanitized[key] = sanitizeString(value);
904
+ break;
905
+
906
+ case 'value':
907
+ sanitized[key] = typeof value === 'number' ? value : parseFloat(value);
908
+ break;
909
+
910
+ case 'currency':
911
+ sanitized[key] = sanitizeString(value);
912
+ break;
913
+
914
+ default:
915
+ // Outros campos são sanitizados como strings
916
+ if (typeof value === 'string') {
917
+ sanitized[key] = sanitizeString(value);
918
+ } else {
919
+ sanitized[key] = value;
920
+ }
921
+ }
922
+ }
923
+
924
+ return sanitized;
925
+ }
926
+ ```
927
+
928
+ ### 3.3 CSRF Protection (Anti-Cross-Site Request Forgery)
929
+
930
+ CSRF Ć© relevante nos **endpoints de webhook** (Hotmart, Kiwify, Ticto) onde um atacante pode forjar requisiƧƵes. A proteção Ć© HMAC-SHA256 por assinatura — cada plataforma assina o payload com um secret compartilhado.
931
+
932
+ ```typescript
933
+ /**
934
+ * Verificação CSRF via HMAC-SHA256 para webhooks de plataformas de pagamento.
935
+ * Cada plataforma tem seu próprio header e algoritmo.
936
+ *
937
+ * @param {Request} request
938
+ * @param {Object} env
939
+ * @param {string} gateway - 'hotmart' | 'kiwify' | 'ticto' | 'stripe'
940
+ * @returns {Promise<boolean>} true se assinatura vƔlida
941
+ */
942
+ export async function validateWebhookSignature(request, env, gateway) {
943
+ const body = await request.text(); // Ler como texto para HMAC exato
944
+
945
+ switch (gateway) {
946
+ case 'hotmart': {
947
+ // Hotmart: header X-Hotmart-Hottok (token fixo, não HMAC)
948
+ const token = request.headers.get('X-Hotmart-Hottok');
949
+ return token === env.WEBHOOK_SECRET_HOTMART;
950
+ }
951
+
952
+ case 'kiwify': {
953
+ // Kiwify: query param ?signature=HMAC_SHA256(body, secret)
954
+ const url = new URL(request.url);
955
+ const receivedSig = url.searchParams.get('signature') || '';
956
+ const expectedSig = await hmacSHA256(body, env.WEBHOOK_SECRET_KIWIFY);
957
+ return timingSafeEqual(receivedSig, expectedSig);
958
+ }
959
+
960
+ case 'ticto': {
961
+ // Ticto: header X-Ticto-Signature = HMAC_SHA256(body, secret)
962
+ const receivedSig = request.headers.get('X-Ticto-Signature') || '';
963
+ const expectedSig = await hmacSHA256(body, env.WEBHOOK_SECRET_TICTO);
964
+ return timingSafeEqual(receivedSig, expectedSig);
965
+ }
966
+
967
+ case 'stripe': {
968
+ // Stripe: header Stripe-Signature = t={ts},v1={HMAC}
969
+ const sigHeader = request.headers.get('Stripe-Signature') || '';
970
+ const parts = Object.fromEntries(sigHeader.split(',').map(p => p.split('=')));
971
+ const signedPayload = `${parts.t}.${body}`;
972
+ const expectedSig = await hmacSHA256(signedPayload, env.STRIPE_WEBHOOK_SECRET);
973
+ return timingSafeEqual(parts.v1, expectedSig);
974
+ }
975
+
976
+ default:
977
+ return false; // Gateway desconhecido = rejeitar
978
+ }
979
+ }
980
+
981
+ // HMAC-SHA256 usando WebCrypto (disponĆ­vel em Cloudflare Workers)
982
+ async function hmacSHA256(message, secret) {
983
+ const encoder = new TextEncoder();
984
+ const key = await crypto.subtle.importKey(
985
+ 'raw', encoder.encode(secret),
986
+ { name: 'HMAC', hash: 'SHA-256' },
987
+ false, ['sign']
988
+ );
989
+ const sig = await crypto.subtle.sign('HMAC', key, encoder.encode(message));
990
+ return Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, '0')).join('');
991
+ }
992
+
993
+ // Comparação em tempo constante — previne timing attacks
994
+ function timingSafeEqual(a, b) {
995
+ if (a.length !== b.length) return false;
996
+ let diff = 0;
997
+ for (let i = 0; i < a.length; i++) {
998
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
999
+ }
1000
+ return diff === 0;
1001
+ }
1002
+
1003
+ /**
1004
+ * Uso no handler de webhook:
1005
+ *
1006
+ * const isValid = await validateWebhookSignature(request, env, 'hotmart');
1007
+ * if (!isValid) return new Response('Unauthorized', { status: 401 });
1008
+ *
1009
+ * REGRA: Validar assinatura ANTES de parsear o body JSON.
1010
+ * Re-clonar o request se precisar ler o body depois:
1011
+ * const clonedRequest = request.clone();
1012
+ * const valid = await validateWebhookSignature(clonedRequest, env, gateway);
1013
+ * const body = await request.json(); // original ainda disponĆ­vel
1014
+ */
1015
+ ```
1016
+
1017
+ ### Checklist CSRF
1018
+
1019
+ - [ ] HMAC validado para Hotmart, Kiwify, Ticto antes de processar
1020
+ - [ ] Rejeição 401 imediata se assinatura invÔlida
1021
+ - [ ] Uso de `timingSafeEqual` para prevenir timing attacks
1022
+ - [ ] Body lido como texto para HMAC (nĆ£o como JSON — evita parsing antes da validação)
1023
+ - [ ] Secrets via `wrangler secret put WEBHOOK_SECRET_HOTMART` etc.
1024
+
1025
+ ---
1026
+
1027
+ ### 3.4 Middleware de Validação e Sanitização
1028
+
1029
+ ```typescript
1030
+ // Middleware de seguranƧa completo
1031
+ export async function applySecurityMiddleware(request, env) {
1032
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
1033
+ const userAgent = request.headers.get('User-Agent') || 'unknown';
1034
+
1035
+ try {
1036
+ // 1. Ler e validar corpo da requisição
1037
+ const eventData = await request.json();
1038
+
1039
+ if (!eventData) {
1040
+ await logSecurityEvent({
1041
+ type: 'MISSING_BODY',
1042
+ severity: 'HIGH',
1043
+ ip,
1044
+ user_agent: userAgent
1045
+ });
1046
+
1047
+ return new Response('Request body is required', {
1048
+ status: 400,
1049
+ headers: { 'Content-Type': 'application/json' }
1050
+ });
1051
+ }
1052
+
1053
+ // 2. Identificar tipo de evento
1054
+ const eventName = eventData.event_name || 'unknown';
1055
+
1056
+ // 3. Sanitizar payload
1057
+ const sanitizedData = sanitizePayload(eventData, eventName);
1058
+
1059
+ // 4. Validar contra schema
1060
+ const validation = await validateEvent(sanitizedData, eventName);
1061
+
1062
+ if (!validation.valid) {
1063
+ await logSecurityEvent({
1064
+ type: 'VALIDATION_FAILED',
1065
+ severity: 'HIGH',
1066
+ ip,
1067
+ user_agent: userAgent,
1068
+ event_name: eventName,
1069
+ details: {
1070
+ sanitized_data: sanitizedData,
1071
+ validation_errors: validation.errors
1072
+ }
1073
+ });
1074
+
1075
+ return new Response(JSON.stringify({
1076
+ error: 'Validation failed',
1077
+ errors: validation.errors
1078
+ }), {
1079
+ status: 400,
1080
+ headers: { 'Content-Type': 'application/json' }
1081
+ });
1082
+ }
1083
+
1084
+ // 5. Aplicar rate limiting
1085
+ const rateLimitResult = await applyRateLimiting(request, env);
1086
+
1087
+ if (!rateLimitResult.allowed) {
1088
+ return new Response(JSON.stringify({
1089
+ error: 'Rate limit exceeded',
1090
+ reason: rateLimitResult.reason,
1091
+ retry_after: rateLimitResult.retryAfter
1092
+ }), {
1093
+ status: 429,
1094
+ headers: getRateLimitHeaders(rateLimitResult)
1095
+ });
1096
+ }
1097
+
1098
+ // 6. Verificar IP blocking
1099
+ const ipBlockResult = await checkIPBlocking(request, env);
1100
+
1101
+ if (!ipBlockResult.allowed) {
1102
+ return new Response(JSON.stringify({
1103
+ error: 'IP blocked',
1104
+ reason: ipBlockResult.reason,
1105
+ block_details: ipBlockResult
1106
+ }), {
1107
+ status: 403,
1108
+ headers: {
1109
+ 'Content-Type': 'application/json',
1110
+ 'X-Block-Reason': ipBlockResult.reason
1111
+ }
1112
+ });
1113
+ }
1114
+
1115
+ // 7. Retornar dados sanitizados e validados
1116
+ return {
1117
+ allowed: true,
1118
+ data: validation.data,
1119
+ sanitized_data: sanitizedData,
1120
+ bypass_rate_limit: rateLimitResult.bypass_rate_limit
1121
+ };
1122
+
1123
+ } catch (error) {
1124
+ await logSecurityEvent({
1125
+ type: 'SECURITY_MIDDLEWARE_EXCEPTION',
1126
+ severity: 'CRITICAL',
1127
+ ip,
1128
+ user_agent: userAgent,
1129
+ details: {
1130
+ error: error.message,
1131
+ stack: error.stack
1132
+ }
1133
+ });
1134
+
1135
+ return new Response(JSON.stringify({
1136
+ error: 'Security validation failed'
1137
+ }), {
1138
+ status: 500,
1139
+ headers: { 'Content-Type': 'application/json' }
1140
+ });
1141
+ }
1142
+ }
1143
+ ```
1144
+
1145
+ ---
1146
+
1147
+ ## šŸ”’ PASSO 4 — ENCRYPTION (ENCRYPTAƇƃO DE PII)
1148
+
1149
+ ### 4.1 Configuração de Encryption
1150
+
1151
+ ```typescript
1152
+ // Configuração de encryption
1153
+ const ENCRYPTION_CONFIG = {
1154
+ // Algoritmos de hash (para enviar Ć s plataformas)
1155
+ hashing: {
1156
+ algorithm: 'SHA256',
1157
+ encoding: 'utf-8',
1158
+ output_format: 'hex'
1159
+ },
1160
+
1161
+ // Encriptação de dados sensíveis no D1
1162
+ encryption: {
1163
+ enabled: true,
1164
+ algorithm: 'AES-256-GCM',
1165
+ key_source: 'CLOUDFLARE_KMS', // Usar Cloudflare KMS para gerenciar chaves
1166
+ key_rotation_days: 90, // Rotacionar chaves a cada 90 dias
1167
+ iv_length: 12
1168
+ tag_length: 16
1169
+ },
1170
+
1171
+ // Campos sensĆ­veis (PII) que devem ser encriptados
1172
+ pii_fields: [
1173
+ 'email',
1174
+ 'phone',
1175
+ 'name',
1176
+ 'first_name',
1177
+ 'last_name',
1178
+ 'city',
1179
+ 'state',
1180
+ 'cep',
1181
+ 'address',
1182
+ 'ip_address'
1183
+ ]
1184
+ };
1185
+ ```
1186
+
1187
+ ### 4.2 Hashing Functions (SHA256 - Web Crypto API)
1188
+
1189
+ ```typescript
1190
+ // Hashing de email
1191
+ export async function hashEmail(email) {
1192
+ if (!email) return null;
1193
+
1194
+ const normalized = email.toLowerCase().trim();
1195
+ const encoder = new TextEncoder();
1196
+
1197
+ const data = encoder.encode(normalized);
1198
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1199
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1200
+
1201
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1202
+ return hashHex;
1203
+ }
1204
+
1205
+ // Hashing de telefone
1206
+ export async function hashPhone(phone) {
1207
+ if (!phone) return null;
1208
+
1209
+ // Normalizar: apenas nĆŗmeros + DDI 55
1210
+ let normalized = phone.replace(/\D/g, '');
1211
+ if (!normalized.startsWith('55')) {
1212
+ normalized = '55' + normalized;
1213
+ }
1214
+
1215
+ const encoder = new TextEncoder();
1216
+ const data = encoder.encode(normalized);
1217
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1218
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1219
+
1220
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1221
+ return hashHex;
1222
+ }
1223
+
1224
+ // Hashing de nome (firstName)
1225
+ export async function hashFirstName(firstName) {
1226
+ if (!firstName) return null;
1227
+
1228
+ const normalized = firstName.toLowerCase().trim();
1229
+ const encoder = new TextEncoder();
1230
+ const data = encoder.encode(normalized);
1231
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1232
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1233
+
1234
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1235
+ return hashHex;
1236
+ }
1237
+
1238
+ // Hashing de nome (lastName)
1239
+ export async function hashLastName(lastName) {
1240
+ if (!lastName) return null;
1241
+
1242
+ const normalized = lastName.toLowerCase().trim();
1243
+ const encoder = new TextEncoder();
1244
+ const data = encoder.encode(normalized);
1245
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1246
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1247
+
1248
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1249
+ return hashHex;
1250
+ }
1251
+
1252
+ // Hashing de cidade
1253
+ export async function hashCity(city) {
1254
+ if (!city) return null;
1255
+
1256
+ // Normalizar: lowercase, sem acentos, sem espaƧos
1257
+ let normalized = city.toLowerCase().trim();
1258
+
1259
+ // Remover acentos
1260
+ normalized = normalized.normalize('NFD')
1261
+ .replace(/[\u0300-\u036f]/g, '');
1262
+
1263
+ // Remover caracteres não-alfanuméricos
1264
+ normalized = normalized.replace(/[^a-z0-9]/g, '');
1265
+
1266
+ const encoder = new TextEncoder();
1267
+ const data = encoder.encode(normalized);
1268
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1269
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1270
+
1271
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1272
+ return hashHex;
1273
+ }
1274
+
1275
+ // Hashing de estado (UF)
1276
+ export async function hashState(state) {
1277
+ if (!state) return null;
1278
+
1279
+ const normalized = state.toLowerCase().trim();
1280
+ const encoder = new TextEncoder();
1281
+ const data = encoder.encode(normalized);
1282
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1283
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1284
+
1285
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1286
+ return hashHex;
1287
+ }
1288
+
1289
+ // Hashing de CEP
1290
+ export async function hashCEP(cep) {
1291
+ if (!cep) return null;
1292
+
1293
+ const normalized = cep.replace(/\D/g, '').trim();
1294
+ const encoder = new TextEncoder();
1295
+ const data = encoder.encode(normalized);
1296
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
1297
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
1298
+
1299
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1300
+ return hashHex;
1301
+ }
1302
+ ```
1303
+
1304
+ ### 4.3 Encryption Functions (AES-256-GCM)
1305
+
1306
+ ```typescript
1307
+ // Encriptação de dados sensíveis
1308
+ const encryptionKeys = new Map();
1309
+
1310
+ async function getOrGenerateKey(field) {
1311
+ // Verificar se jĆ” temos chave
1312
+ if (encryptionKeys.has(field)) {
1313
+ return encryptionKeys.get(field);
1314
+ }
1315
+
1316
+ // Gerar nova chave
1317
+ const key = await crypto.subtle.generateKey(
1318
+ 'AES-GCM',
1319
+ { length: 256 },
1320
+ true,
1321
+ ['encrypt', 'decrypt']
1322
+ );
1323
+
1324
+ encryptionKeys.set(field, key);
1325
+ return key;
1326
+ }
1327
+
1328
+ // Encriptar campo PII
1329
+ export async function encryptPII(field, plaintext) {
1330
+ if (!ENCRYPTION_CONFIG.encryption.enabled || !plaintext) {
1331
+ return plaintext; // Retorna texto claro se encryption desabilitado
1332
+ }
1333
+
1334
+ if (!ENCRYPTION_CONFIG.pii_fields.includes(field)) {
1335
+ return plaintext; // Campo não é PII, retorna texto claro
1336
+ }
1337
+
1338
+ try {
1339
+ const key = await getOrGenerateKey(field);
1340
+ const iv = crypto.getRandomValues(new Uint8Array(ENCRYPTION_CONFIG.encryption.iv_length));
1341
+ const tag = crypto.getRandomValues(new Uint8Array(ENCRYPTION_CONFIG.encryption.tag_length));
1342
+
1343
+ const encoder = new TextEncoder();
1344
+ const encodedPlaintext = encoder.encode(plaintext);
1345
+
1346
+ const encryptedData = await crypto.subtle.encrypt(
1347
+ {
1348
+ name: 'AES-GCM',
1349
+ iv: iv
1350
+ },
1351
+ key,
1352
+ encodedPlaintext,
1353
+ false
1354
+ );
1355
+
1356
+ const ivHex = Array.from(iv).map(b => b.toString(16).padStart(2, '0')).join('');
1357
+ const tagHex = Array.from(tag).map(b => b.toString(16).padStart(2, '0')).join('');
1358
+ const ciphertextHex = Array.from(new Uint8Array(encryptedData.ciphertext)).map(b => b.toString(16).padStart(2, '0')).join('');
1359
+
1360
+ const encrypted = `${ivHex}:${ciphertextHex}:${tagHex}`;
1361
+
1362
+ return encrypted;
1363
+
1364
+ } catch (error) {
1365
+ console.error(`Encryption error for field ${field}:`, error);
1366
+ return plaintext; // Retorna texto claro se falhar
1367
+ }
1368
+ }
1369
+
1370
+ // Decriptar campo PII
1371
+ export async function decryptPII(field, encrypted) {
1372
+ if (!ENCRYPTION_CONFIG.encryption.enabled || !encrypted) {
1373
+ return encrypted; // Retorna como estĆ” se encryption desabilitado
1374
+ }
1375
+
1376
+ if (!ENCRYPTION_CONFIG.pii_fields.includes(field)) {
1377
+ return encrypted; // Campo não é PII, retorna como estÔ
1378
+ }
1379
+
1380
+ try {
1381
+ const key = await getOrGenerateKey(field);
1382
+
1383
+ const [ivHex, ciphertextHex, tagHex] = encrypted.split(':');
1384
+
1385
+ const iv = new Uint8Array(ivHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
1386
+ const ciphertext = new Uint8Array(ciphertextHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
1387
+ const tag = new Uint8Array(tagHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
1388
+
1389
+ const decryptedData = await crypto.subtle.decrypt(
1390
+ {
1391
+ name: 'AES-GCM',
1392
+ iv: iv
1393
+ tag: tag
1394
+ },
1395
+ key,
1396
+ ciphertext,
1397
+ tag
1398
+ );
1399
+
1400
+ const decoder = new TextDecoder();
1401
+ const plaintext = decoder.decode(decryptedData);
1402
+
1403
+ return plaintext;
1404
+
1405
+ } catch (error) {
1406
+ console.error(`Decryption error for field ${field}:`, error);
1407
+ return encrypted; // Retorna encriptado se falhar
1408
+ }
1409
+ }
1410
+ ```
1411
+
1412
+ ---
1413
+
1414
+ ## šŸ“‹ PASSO 5 — AUDIT LOGGING (LOGGING DE SEGURANƇA)
1415
+
1416
+ ### 5.1 Schema D1 para Audit Logs
1417
+
1418
+ ```sql
1419
+ -- Tabela de audit logs de seguranƧa
1420
+ CREATE TABLE IF NOT EXISTS audit_logs (
1421
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
1422
+ timestamp DATETIME NOT NULL,
1423
+ ip TEXT NOT NULL,
1424
+ user_id TEXT,
1425
+ session_id TEXT,
1426
+ user_agent TEXT,
1427
+ event_name TEXT,
1428
+ event_id TEXT,
1429
+ log_type TEXT NOT NULL,
1430
+ severity TEXT NOT NULL,
1431
+ action TEXT NOT NULL,
1432
+ outcome TEXT NOT NULL,
1433
+ details TEXT,
1434
+ blocked BOOLEAN,
1435
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
1436
+ );
1437
+
1438
+ CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_logs(timestamp);
1439
+ CREATE INDEX IF NOT EXISTS idx_audit_ip ON audit_logs(ip);
1440
+ CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_logs(user_id);
1441
+ CREATE INDEX IF NOT EXISTS idx_audit_session ON audit_logs(session_id);
1442
+ CREATE INDEX IF NOT EXISTS idx_audit_event_name ON audit_logs(event_name);
1443
+ CREATE INDEX IF NOT EXISTS idx_audit_log_type ON audit_logs(log_type);
1444
+ CREATE INDEX IF NOT EXISTS idx_audit_severity ON audit_logs(severity);
1445
+ CREATE INDEX IF NOT EXISTS idx_audit_blocked ON audit_logs(blocked);
1446
+ ```
1447
+
1448
+ ### 5.2 Tipos de Audit Log
1449
+
1450
+ ```typescript
1451
+ // Tipos de log de seguranƧa
1452
+ const AUDIT_LOG_TYPES = {
1453
+ // Rate Limiting
1454
+ RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
1455
+ IP_RATE_LIMIT_EXCEEDED: 'IP_RATE_LIMIT_EXCEEDED',
1456
+ USER_RATE_LIMIT_EXCEEDED: 'USER_RATE_LIMIT_EXCEEDED',
1457
+ EVENT_RATE_LIMIT_EXCEEDED: 'EVENT_RATE_LIMIT_EXCEEDED',
1458
+ GLOBAL_RATE_LIMIT_EXCEEDED: 'GLOBAL_RATE_LIMIT_EXCEEDED',
1459
+
1460
+ // IP Blocking
1461
+ IP_BLACKLISTED: 'IP_BLACKLISTED',
1462
+ IP_AUTO_BLOCKED: 'IP_AUTO_BLOCKED',
1463
+ IP_GEO_BLOCKED: 'IP_GEO_BLOCKED',
1464
+ IP_WHITELISTED: 'IP_WHITELISTED',
1465
+
1466
+ // Validation
1467
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
1468
+ VALIDATION_EXCEPTION: 'VALIDATION_EXCEPTION',
1469
+ VALIDATION_FAILED: 'VALIDATION_FAILED',
1470
+ MISSING_BODY: 'MISSING_BODY',
1471
+
1472
+ // Sanitization
1473
+ SANITIZATION_APPLIED: 'SANITIZATION_APPLIED',
1474
+ XSS_ATTEMPT: 'XSS_ATTEMPT',
1475
+ SQL_INJECTION_ATTEMPT: 'SQL_INJECTION_ATTEMPT',
1476
+ EMAIL_INJECTION_ATTEMPT: 'EMAIL_INJECTION_ATTEMPT',
1477
+ PHONE_INJECTION_ATTEMPT: 'PHONE_INJECTION_ATTEMPT',
1478
+ URL_INJECTION_ATTEMPT: 'URL_INJECTION_ATTEMPT',
1479
+
1480
+ // Encryption
1481
+ ENCRYPTION_ERROR: 'ENCRYPTION_ERROR',
1482
+ DECRYPTION_ERROR: 'DECRYPTION_ERROR',
1483
+ KEY_ROTATION: 'KEY_ROTATION',
1484
+
1485
+ // Security Middleware
1486
+ SECURITY_MIDDLEWARE_EXCEPTION: 'SECURITY_MIDDLEWARE_EXCEPTION'
1487
+ };
1488
+
1489
+ // NĆ­veis de severidade
1490
+ const SEVERITY_LEVELS = {
1491
+ CRITICAL: 'CRITICAL',
1492
+ HIGH: 'HIGH',
1493
+ MEDIUM: 'MEDIUM',
1494
+ LOW: 'LOW',
1495
+ INFO: 'INFO'
1496
+ };
1497
+ ```
1498
+
1499
+ ### 5.3 FunƧƵes de Audit Logging
1500
+
1501
+ ```typescript
1502
+ // Log de evento de seguranƧa
1503
+ export async function logSecurityEvent(eventData, env) {
1504
+ const {
1505
+ type,
1506
+ severity,
1507
+ ip = 'unknown',
1508
+ user_id = null,
1509
+ session_id = null,
1510
+ user_agent = null,
1511
+ event_name = null,
1512
+ event_id = null,
1513
+ action,
1514
+ outcome,
1515
+ details = null,
1516
+ blocked = false
1517
+ } = eventData;
1518
+
1519
+ const timestamp = new Date().toISOString();
1520
+
1521
+ await env.DB.prepare(`
1522
+ INSERT INTO audit_logs
1523
+ (timestamp, ip, user_id, session_id, user_agent, event_name, event_id,
1524
+ log_type, severity, action, outcome, details, blocked)
1525
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1526
+ `).bind(
1527
+ timestamp,
1528
+ ip,
1529
+ user_id,
1530
+ session_id,
1531
+ user_agent,
1532
+ event_name,
1533
+ event_id,
1534
+ type,
1535
+ severity,
1536
+ action || 'LOG_EVENT',
1537
+ outcome || 'SUCCESS',
1538
+ JSON.stringify(details),
1539
+ blocked ? 1 : 0
1540
+ ).run();
1541
+
1542
+ // Log crĆ­tico no console
1543
+ if (severity === 'CRITICAL' || severity === 'HIGH') {
1544
+ console.error(`🚨 ${severity} [${type}]:`, {
1545
+ ip,
1546
+ user_id,
1547
+ event_name,
1548
+ action,
1549
+ details
1550
+ });
1551
+ }
1552
+ }
1553
+
1554
+ // Query de audit logs
1555
+ export async function queryAuditLogs(filters = {}, env) {
1556
+ const {
1557
+ ip,
1558
+ user_id,
1559
+ session_id,
1560
+ event_name,
1561
+ log_type,
1562
+ severity,
1563
+ blocked,
1564
+ start_date,
1565
+ end_date,
1566
+ limit = 100
1567
+ } = filters;
1568
+
1569
+ let query = 'SELECT * FROM audit_logs WHERE 1=1';
1570
+ const params = [];
1571
+
1572
+ if (ip) {
1573
+ query += ' AND ip = ?';
1574
+ params.push(ip);
1575
+ }
1576
+ if (user_id) {
1577
+ query += ' AND user_id = ?';
1578
+ params.push(user_id);
1579
+ }
1580
+ if (session_id) {
1581
+ query += ' AND session_id = ?';
1582
+ params.push(session_id);
1583
+ }
1584
+ if (event_name) {
1585
+ query += ' AND event_name = ?';
1586
+ params.push(event_name);
1587
+ }
1588
+ if (log_type) {
1589
+ query += ' AND log_type = ?';
1590
+ params.push(log_type);
1591
+ }
1592
+ if (severity) {
1593
+ query += ' AND severity = ?';
1594
+ params.push(severity);
1595
+ }
1596
+ if (blocked !== undefined) {
1597
+ query += ' AND blocked = ?';
1598
+ params.push(blocked ? 1 : 0);
1599
+ }
1600
+ if (start_date) {
1601
+ query += ' AND timestamp >= ?';
1602
+ params.push(start_date);
1603
+ }
1604
+ if (end_date) {
1605
+ query += ' AND timestamp <= ?';
1606
+ params.push(end_date);
1607
+ }
1608
+
1609
+ query += ' ORDER BY timestamp DESC LIMIT ?';
1610
+
1611
+ const results = await env.DB.prepare(query).bind(...params).all();
1612
+
1613
+ return results;
1614
+ }
1615
+ ```
1616
+
1617
+ ---
1618
+
1619
+ ## šŸ”§ PASSO 6 — ENDPOINTS DE SEGURANƇA
1620
+
1621
+ ### 6.1 Endpoint: `/api/security/rate-limit-status`
1622
+
1623
+ ```typescript
1624
+ export async function getRateLimitStatus(request, env) {
1625
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
1626
+
1627
+ const stats = {
1628
+ ip,
1629
+ rate_limits: {
1630
+ ip: rateLimiters.ip.has(ip) ? {
1631
+ remaining: rateLimiters.ip.get(ip).tokens,
1632
+ capacity: rateLimiters.ip.get(ip).capacity,
1633
+ refill_rate: rateLimiters.ip.get(ip).refillRate
1634
+ } : null,
1635
+ global: {
1636
+ remaining: rateLimiters.event.get('global').tokens,
1637
+ capacity: rateLimiters.event.get('global').capacity,
1638
+ refill_rate: rateLimiters.event.get('global').refillRate
1639
+ }
1640
+ },
1641
+ recent_violations: await env.DB.prepare(`
1642
+ SELECT
1643
+ log_type,
1644
+ severity,
1645
+ COUNT(*) as violations
1646
+ FROM audit_logs
1647
+ WHERE ip = ?
1648
+ AND created_at > datetime('now', '-1 hour')
1649
+ GROUP BY log_type, severity
1650
+ ORDER BY violations DESC
1651
+ `).bind(ip).all()
1652
+ };
1653
+
1654
+ return new Response(JSON.stringify(stats), {
1655
+ headers: { 'Content-Type': 'application/json' },
1656
+ status: 200
1657
+ });
1658
+ }
1659
+ ```
1660
+
1661
+ ### 6.2 Endpoint: `/api/security/ip-status`
1662
+
1663
+ ```typescript
1664
+ export async function getIPStatus(request, env) {
1665
+ const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
1666
+
1667
+ // Verificar status do IP
1668
+ const blacklist = await checkIPBlacklist(ip, env);
1669
+ const whitelist = await checkIPWhitelist(ip, env);
1670
+ const geoBlock = await checkGeoBlocking(request, env);
1671
+
1672
+ const status = {
1673
+ ip,
1674
+ is_whitelisted: whitelist,
1675
+ is_blacklisted: !!blacklist,
1676
+ blacklist_reason: blacklist ? blacklist.block_reason : null,
1677
+ is_geo_blocked: !!geoBlock,
1678
+ geo_details: geoBlock || null,
1679
+ recent_violations: await env.DB.prepare(`
1680
+ SELECT
1681
+ COUNT(*) as violations,
1682
+ MAX(violation_count) as max_violation_count
1683
+ FROM ip_blacklist
1684
+ WHERE ip = ?
1685
+ AND unblocked_at IS NULL
1686
+ AND blocked_at > datetime('now', '-24 hours')
1687
+ `).bind(ip).get()
1688
+ };
1689
+
1690
+ return new Response(JSON.stringify(status), {
1691
+ headers: { 'Content-Type': 'application/json' },
1692
+ status: 200
1693
+ });
1694
+ }
1695
+ ```
1696
+
1697
+ ### 6.3 Endpoint: `/api/security/audit-logs`
1698
+
1699
+ ```typescript
1700
+ export async function getAuditLogs(request, env) {
1701
+ const url = new URL(request.url);
1702
+ const filters = {
1703
+ ip: url.searchParams.get('ip'),
1704
+ user_id: url.searchParams.get('user_id'),
1705
+ session_id: url.searchParams.get('session_id'),
1706
+ event_name: url.searchParams.get('event_name'),
1707
+ log_type: url.searchParams.get('log_type'),
1708
+ severity: url.searchParams.get('severity'),
1709
+ blocked: url.searchParams.get('blocked'),
1710
+ start_date: url.searchParams.get('start_date'),
1711
+ end_date: url.searchParams.get('end_date'),
1712
+ limit: parseInt(url.searchParams.get('limit') || '100')
1713
+ };
1714
+
1715
+ const logs = await queryAuditLogs(filters);
1716
+
1717
+ return new Response(JSON.stringify({
1718
+ logs,
1719
+ total_count: logs.length,
1720
+ filters
1721
+ }), {
1722
+ headers: { 'Content-Type': 'application/json' },
1723
+ status: 200
1724
+ });
1725
+ }
1726
+ ```
1727
+
1728
+ ---
1729
+
1730
+ ## šŸŽÆ FORMATO DE SAƍDA
1731
+
1732
+ ### DELIVERABLE 1: `modules/security-middleware.ts`
1733
+
1734
+ ```typescript
1735
+ // modules/security-middleware.ts - Middleware de seguranƧa completo
1736
+ export {
1737
+ applyRateLimiting,
1738
+ checkIPBlocking,
1739
+ validateEvent,
1740
+ sanitizePayload,
1741
+ applySecurityMiddleware,
1742
+ hashEmail,
1743
+ hashPhone,
1744
+ hashFirstName,
1745
+ hashLastName,
1746
+ hashCity,
1747
+ hashState,
1748
+ hashCEP,
1749
+ encryptPII,
1750
+ decryptPII,
1751
+ logSecurityEvent,
1752
+ queryAuditLogs
1753
+ };
1754
+ ```
1755
+
1756
+ ### DELIVERABLE 2: `security-schema.sql`
1757
+
1758
+ ```sql
1759
+ -- security-schema.sql - Schema D1 para seguranƧa
1760
+ CREATE TABLE IF NOT EXISTS ip_blacklist (...);
1761
+ CREATE TABLE IF NOT EXISTS ip_whitelist (...);
1762
+ CREATE TABLE IF NOT EXISTS ip_violations (...);
1763
+ CREATE TABLE IF NOT EXISTS audit_logs (...);
1764
+ ```
1765
+
1766
+ ### DELIVERABLE 3: `security-config.js`
1767
+
1768
+ ```typescript
1769
+ // security-config.js - Configuração de segurança
1770
+ export const RATE_LIMIT_CONFIG = { ... };
1771
+ export const IP_BLOCKING_CONFIG = { ... };
1772
+ export const ENCRYPTION_CONFIG = { ... };
1773
+ export const AUDIT_LOG_TYPES = { ... };
1774
+ export const SEVERITY_LEVELS = { ... };
1775
+ ```
1776
+
1777
+ ---
1778
+
1779
+ ## šŸ“Š CHECKLIST DE IMPLEMENTAƇƃO
1780
+
1781
+ ### Rate Limiting
1782
+
1783
+ - [ ] Token bucket algorithm implementado
1784
+ - [ ] Rate limiting por IP implementado
1785
+ - [ ] Rate limiting por usuƔrio implementado
1786
+ - [ ] Rate limiting por evento implementado
1787
+ - [ ] Rate limiting global implementado
1788
+ - [ ] Headers de rate limit implementados
1789
+ - [ ] Exponential backoff implementado
1790
+
1791
+ ### IP Blocking
1792
+
1793
+ - [ ] Blacklist de IPs criada
1794
+ - [ ] Whitelist de IPs criada
1795
+ - [ ] Bloqueio automƔtico por falhas implementado
1796
+ - [ ] Bloqueio automƔtico por 429 implementado
1797
+ - [ ] Geoblocking implementado
1798
+ - [ ] CIDR ranges implementados
1799
+ - [ ] Auto-unblock implementado
1800
+
1801
+ ### CSRF Protection (Webhooks)
1802
+
1803
+ - [ ] HMAC-SHA256 validado para Hotmart
1804
+ - [ ] HMAC-SHA256 validado para Kiwify
1805
+ - [ ] HMAC-SHA256 validado para Ticto
1806
+ - [ ] HMAC-SHA256 validado para Stripe
1807
+ - [ ] `timingSafeEqual` implementado (sem timing attacks)
1808
+ - [ ] Body lido como text antes do JSON.parse para validação HMAC
1809
+ - [ ] Secrets via `wrangler secret put` (nunca hardcode)
1810
+
1811
+ ### Input Validation
1812
+
1813
+ - [ ] Joi schemas criados (Lead, Purchase, Contact)
1814
+ - [ ] Validação de email implementada
1815
+ - [ ] Validação de telefone implementada
1816
+ - [ ] Validação de URL implementada
1817
+ - [ ] Validação de user_agent implementada
1818
+ - [ ] Sanitização de strings implementada
1819
+ - [ ] Sanitização anti-XSS implementada
1820
+ - [ ] Sanitização anti-injection implementada
1821
+
1822
+ ### Encryption
1823
+
1824
+ - [ ] SHA256 hashing implementado (email, phone, nome, cidade)
1825
+ - [ ] Normalização de dados implementada
1826
+ - [ ] AES-256-GCM encryption implementada
1827
+ - [ ] Encriptação de PII no D1 implementada
1828
+ - [ ] Decriptação de PII implementada
1829
+ - [ ] Geração de chaves implementada
1830
+
1831
+ ### Audit Logging
1832
+
1833
+ - [ ] Schema D1 para audit logs criado
1834
+ - [ ] Tipos de log de seguranƧa criados
1835
+ - [ ] Função de log de eventos implementada
1836
+ - [ ] Query de audit logs implementada
1837
+ - [ ] Bloqueio de IPs logado
1838
+ - [ ] ValidaƧƵes falhas logadas
1839
+
1840
+ ### Endpoints
1841
+
1842
+ - [ ] GET /api/security/rate-limit-status implementado
1843
+ - [ ] GET /api/security/ip-status implementado
1844
+ - [ ] GET /api/security/audit-logs implementado
1845
+ - [ ] Headers de seguranƧa implementados
1846
+
1847
+ ---
1848
+
1849
+ ## šŸŽÆ BENEFƍCIOS ESPERADOS
1850
+
1851
+ 1. **Proteção contra abuso** — Rate limiting impede flooding
1852
+ 2. **Proteção contra ataques** — IP blocking impede IPs maliciosos
1853
+ 3. **Validação profissional** — Joi schemas validam entrada rigorosamente
1854
+ 4. **Sanitização robusta** — Anti-XSS e anti-injection
1855
+ 5. **Encryption de PII** — Dados sensĆ­veis protegidos no D1
1856
+ 6. **Audit logging completo** - Quem fez o quĆŖ, quando, onde
1857
+ 7. **Compliance ready** - Logs para GDPR/LGPD/CCPA
1858
+
1859
+ ---
1860
+
1861
+ > šŸ”’ **Sua Função:** Implementar camadas de seguranƧa enterprise (rate limiting, IP blocking, input validation, encryption, audit logging) para proteger o sistema server-side contra abuso, ataques e garantir conformidade com normas de seguranƧa.