securenow 4.0.2 → 4.0.5
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.
- package/AUTO-BODY-CAPTURE.md +409 -0
- package/BODY-CAPTURE-FIX.md +258 -0
- package/BODY-CAPTURE-QUICKSTART.md +147 -0
- package/CUSTOMER-GUIDE.md +23 -0
- package/EASIEST-SETUP.md +339 -0
- package/FINAL-SOLUTION.md +332 -0
- package/NEXTJS-BODY-CAPTURE-COMPARISON.md +320 -0
- package/NEXTJS-BODY-CAPTURE.md +368 -0
- package/NEXTJS-GUIDE.md +10 -0
- package/NEXTJS-QUICKSTART.md +1 -1
- package/NEXTJS-WRAPPER-APPROACH.md +411 -0
- package/QUICKSTART-BODY-CAPTURE.md +287 -0
- package/REDACTION-EXAMPLES.md +481 -0
- package/REQUEST-BODY-CAPTURE.md +575 -0
- package/SOLUTION-SUMMARY.md +309 -0
- package/cli.js +1 -1
- package/examples/instrumentation-with-auto-capture.ts +38 -0
- package/examples/nextjs-api-route-with-body-capture.ts +51 -0
- package/examples/nextjs-middleware.js +34 -0
- package/examples/nextjs-middleware.ts +34 -0
- package/nextjs-auto-capture.js +204 -0
- package/nextjs-middleware.js +178 -0
- package/nextjs-wrapper.js +155 -0
- package/nextjs.js +204 -14
- package/package.json +20 -2
- package/postinstall.js +117 -22
- package/tracing.js +154 -1
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
# 🔒 Redaction Examples - See It In Action
|
|
2
|
+
|
|
3
|
+
Real examples of how SecureNow redacts sensitive data across all content types.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## JSON Redaction
|
|
8
|
+
|
|
9
|
+
### Example 1: Login Request
|
|
10
|
+
|
|
11
|
+
**Original Request:**
|
|
12
|
+
```json
|
|
13
|
+
POST /api/login
|
|
14
|
+
Content-Type: application/json
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
"username": "john@example.com",
|
|
18
|
+
"password": "MySecretPass123!",
|
|
19
|
+
"remember": true,
|
|
20
|
+
"device_id": "abc123"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Captured in Trace:**
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"username": "john@example.com",
|
|
28
|
+
"password": "[REDACTED]",
|
|
29
|
+
"remember": true,
|
|
30
|
+
"device_id": "abc123"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Example 2: Payment Request
|
|
35
|
+
|
|
36
|
+
**Original Request:**
|
|
37
|
+
```json
|
|
38
|
+
POST /api/payment
|
|
39
|
+
Content-Type: application/json
|
|
40
|
+
|
|
41
|
+
{
|
|
42
|
+
"amount": 99.99,
|
|
43
|
+
"currency": "USD",
|
|
44
|
+
"card": {
|
|
45
|
+
"number": "4242424242424242",
|
|
46
|
+
"cvv": "123",
|
|
47
|
+
"expiry": "12/25"
|
|
48
|
+
},
|
|
49
|
+
"billing": {
|
|
50
|
+
"name": "John Doe",
|
|
51
|
+
"email": "john@example.com"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Captured in Trace:**
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"amount": 99.99,
|
|
60
|
+
"currency": "USD",
|
|
61
|
+
"card": "[REDACTED]",
|
|
62
|
+
"billing": {
|
|
63
|
+
"name": "John Doe",
|
|
64
|
+
"email": "john@example.com"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
*Note: The entire `card` object is redacted because the key contains "card"*
|
|
69
|
+
|
|
70
|
+
### Example 3: Nested Secrets
|
|
71
|
+
|
|
72
|
+
**Original Request:**
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"user": {
|
|
76
|
+
"name": "John",
|
|
77
|
+
"auth": {
|
|
78
|
+
"password": "secret",
|
|
79
|
+
"api_key": "sk_live_abc123"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"metadata": {
|
|
83
|
+
"session_token": "xyz789"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Captured in Trace:**
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"user": {
|
|
92
|
+
"name": "John",
|
|
93
|
+
"auth": {
|
|
94
|
+
"password": "[REDACTED]",
|
|
95
|
+
"api_key": "[REDACTED]"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"metadata": {
|
|
99
|
+
"session_token": "[REDACTED]"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
*Recursive redaction finds sensitive fields at any depth*
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## GraphQL Redaction
|
|
108
|
+
|
|
109
|
+
### Example 1: Login Mutation
|
|
110
|
+
|
|
111
|
+
**Original Request:**
|
|
112
|
+
```graphql
|
|
113
|
+
POST /graphql
|
|
114
|
+
Content-Type: application/graphql
|
|
115
|
+
|
|
116
|
+
mutation Login {
|
|
117
|
+
login(
|
|
118
|
+
email: "john@example.com",
|
|
119
|
+
password: "MySecretPass123!"
|
|
120
|
+
) {
|
|
121
|
+
token
|
|
122
|
+
user {
|
|
123
|
+
id
|
|
124
|
+
name
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Captured in Trace:**
|
|
131
|
+
```graphql
|
|
132
|
+
mutation Login {
|
|
133
|
+
login(
|
|
134
|
+
email: "john@example.com",
|
|
135
|
+
password: "[REDACTED]"
|
|
136
|
+
) {
|
|
137
|
+
token
|
|
138
|
+
user {
|
|
139
|
+
id
|
|
140
|
+
name
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Example 2: Variables with Secrets
|
|
147
|
+
|
|
148
|
+
**Original Request:**
|
|
149
|
+
```graphql
|
|
150
|
+
mutation CreateUser($input: UserInput!) {
|
|
151
|
+
createUser(input: $input) {
|
|
152
|
+
id
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Variables:
|
|
157
|
+
{
|
|
158
|
+
"input": {
|
|
159
|
+
"email": "john@example.com",
|
|
160
|
+
"password": "secret123",
|
|
161
|
+
"api_key": "sk_test_abc"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Captured in Trace:**
|
|
167
|
+
```graphql
|
|
168
|
+
mutation CreateUser($input: UserInput!) {
|
|
169
|
+
createUser(input: $input) {
|
|
170
|
+
id
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Variables:
|
|
175
|
+
{
|
|
176
|
+
"input": {
|
|
177
|
+
"email": "john@example.com",
|
|
178
|
+
"password": "[REDACTED]",
|
|
179
|
+
"api_key": "[REDACTED]"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Example 3: Multiple Sensitive Fields
|
|
185
|
+
|
|
186
|
+
**Original Request:**
|
|
187
|
+
```graphql
|
|
188
|
+
mutation UpdateAccount {
|
|
189
|
+
updateAccount(
|
|
190
|
+
id: "123",
|
|
191
|
+
password: "newpass",
|
|
192
|
+
secret: "mysecret",
|
|
193
|
+
api_key: "sk_live_xyz"
|
|
194
|
+
) {
|
|
195
|
+
success
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Captured in Trace:**
|
|
201
|
+
```graphql
|
|
202
|
+
mutation UpdateAccount {
|
|
203
|
+
updateAccount(
|
|
204
|
+
id: "123",
|
|
205
|
+
password: "[REDACTED]",
|
|
206
|
+
secret: "[REDACTED]",
|
|
207
|
+
api_key: "[REDACTED]"
|
|
208
|
+
) {
|
|
209
|
+
success
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Form Data Redaction
|
|
217
|
+
|
|
218
|
+
### Example 1: Login Form
|
|
219
|
+
|
|
220
|
+
**Original Request:**
|
|
221
|
+
```http
|
|
222
|
+
POST /api/login
|
|
223
|
+
Content-Type: application/x-www-form-urlencoded
|
|
224
|
+
|
|
225
|
+
username=john&password=secret123&remember=on
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Captured in Trace:**
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"username": "john",
|
|
232
|
+
"password": "[REDACTED]",
|
|
233
|
+
"remember": "on"
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Example 2: Registration Form
|
|
238
|
+
|
|
239
|
+
**Original Request:**
|
|
240
|
+
```http
|
|
241
|
+
POST /api/register
|
|
242
|
+
Content-Type: application/x-www-form-urlencoded
|
|
243
|
+
|
|
244
|
+
email=john@example.com&password=MyPass123&confirm_password=MyPass123&terms=agree
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Captured in Trace:**
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"email": "john@example.com",
|
|
251
|
+
"password": "[REDACTED]",
|
|
252
|
+
"confirm_password": "[REDACTED]",
|
|
253
|
+
"terms": "agree"
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
*Note: "confirm_password" is redacted because it contains "password"*
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Multipart (NOT Captured)
|
|
261
|
+
|
|
262
|
+
### Example: File Upload
|
|
263
|
+
|
|
264
|
+
**Original Request:**
|
|
265
|
+
```http
|
|
266
|
+
POST /api/upload
|
|
267
|
+
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
|
|
268
|
+
|
|
269
|
+
------WebKitFormBoundary
|
|
270
|
+
Content-Disposition: form-data; name="file"; filename="document.pdf"
|
|
271
|
+
Content-Type: application/pdf
|
|
272
|
+
|
|
273
|
+
[Binary PDF data...]
|
|
274
|
+
------WebKitFormBoundary
|
|
275
|
+
Content-Disposition: form-data; name="description"
|
|
276
|
+
|
|
277
|
+
Important document
|
|
278
|
+
------WebKitFormBoundary--
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Captured in Trace:**
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"http.request.body": "[MULTIPART - NOT CAPTURED]",
|
|
285
|
+
"http.request.body.type": "multipart",
|
|
286
|
+
"http.request.body.note": "File uploads not captured by design"
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
*Multipart data is NOT captured at all - too large and unnecessary*
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Custom Sensitive Fields
|
|
294
|
+
|
|
295
|
+
### Configure Custom Fields
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# .env.local
|
|
299
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone,address,ssn,credit_card
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Example with Custom Fields
|
|
303
|
+
|
|
304
|
+
**Original Request:**
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"name": "John Doe",
|
|
308
|
+
"email": "john@example.com",
|
|
309
|
+
"phone": "+1-555-0123",
|
|
310
|
+
"address": "123 Main St",
|
|
311
|
+
"credit_card": "4242424242424242"
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Captured in Trace:**
|
|
316
|
+
```json
|
|
317
|
+
{
|
|
318
|
+
"name": "John Doe",
|
|
319
|
+
"email": "[REDACTED]",
|
|
320
|
+
"phone": "[REDACTED]",
|
|
321
|
+
"address": "[REDACTED]",
|
|
322
|
+
"credit_card": "[REDACTED]"
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Field Matching Rules
|
|
329
|
+
|
|
330
|
+
### Case-Insensitive Matching
|
|
331
|
+
|
|
332
|
+
These all get redacted if "password" is in the sensitive list:
|
|
333
|
+
- `password` → `[REDACTED]`
|
|
334
|
+
- `Password` → `[REDACTED]`
|
|
335
|
+
- `PASSWORD` → `[REDACTED]`
|
|
336
|
+
- `user_password` → `[REDACTED]`
|
|
337
|
+
- `passwordHash` → `[REDACTED]`
|
|
338
|
+
|
|
339
|
+
### Partial Matching (Substring)
|
|
340
|
+
|
|
341
|
+
If "token" is sensitive, these get redacted:
|
|
342
|
+
- `token` → `[REDACTED]`
|
|
343
|
+
- `access_token` → `[REDACTED]`
|
|
344
|
+
- `refresh_token` → `[REDACTED]`
|
|
345
|
+
- `oauth_token` → `[REDACTED]`
|
|
346
|
+
- `stripe_token` → `[REDACTED]`
|
|
347
|
+
|
|
348
|
+
### Built-in Sensitive Fields (20+)
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
[
|
|
352
|
+
'password', 'passwd', 'pwd',
|
|
353
|
+
'secret', 'token', 'api_key', 'apikey',
|
|
354
|
+
'access_token', 'auth', 'credentials',
|
|
355
|
+
'mysql_pwd', 'stripeToken',
|
|
356
|
+
'card', 'cardnumber', 'ccv', 'cvc', 'cvv',
|
|
357
|
+
'ssn', 'pin'
|
|
358
|
+
]
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Edge Cases
|
|
364
|
+
|
|
365
|
+
### 1. Empty Values
|
|
366
|
+
|
|
367
|
+
**Original:**
|
|
368
|
+
```json
|
|
369
|
+
{ "password": "" }
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**Captured:**
|
|
373
|
+
```json
|
|
374
|
+
{ "password": "[REDACTED]" }
|
|
375
|
+
```
|
|
376
|
+
*Even empty sensitive fields are redacted*
|
|
377
|
+
|
|
378
|
+
### 2. Null Values
|
|
379
|
+
|
|
380
|
+
**Original:**
|
|
381
|
+
```json
|
|
382
|
+
{ "password": null }
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Captured:**
|
|
386
|
+
```json
|
|
387
|
+
{ "password": "[REDACTED]" }
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### 3. Numeric Passwords
|
|
391
|
+
|
|
392
|
+
**Original:**
|
|
393
|
+
```json
|
|
394
|
+
{ "password": 123456 }
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Captured:**
|
|
398
|
+
```json
|
|
399
|
+
{ "password": "[REDACTED]" }
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 4. Array of Objects
|
|
403
|
+
|
|
404
|
+
**Original:**
|
|
405
|
+
```json
|
|
406
|
+
{
|
|
407
|
+
"users": [
|
|
408
|
+
{ "name": "John", "password": "pass1" },
|
|
409
|
+
{ "name": "Jane", "password": "pass2" }
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Captured:**
|
|
415
|
+
```json
|
|
416
|
+
{
|
|
417
|
+
"users": [
|
|
418
|
+
{ "name": "John", "password": "[REDACTED]" },
|
|
419
|
+
{ "name": "Jane", "password": "[REDACTED]" }
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Verification
|
|
427
|
+
|
|
428
|
+
### Test Your Redaction
|
|
429
|
+
|
|
430
|
+
1. **Enable body capture:**
|
|
431
|
+
```bash
|
|
432
|
+
SECURENOW_CAPTURE_BODY=1
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
2. **Make a test request:**
|
|
436
|
+
```bash
|
|
437
|
+
curl -X POST http://localhost:3000/api/test \
|
|
438
|
+
-H "Content-Type: application/json" \
|
|
439
|
+
-d '{"username":"test","password":"secret123"}'
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
3. **Check SigNoz:**
|
|
443
|
+
- Find the trace
|
|
444
|
+
- Look for `http.request.body`
|
|
445
|
+
- Verify password shows `[REDACTED]`
|
|
446
|
+
|
|
447
|
+
### Debug Redaction
|
|
448
|
+
|
|
449
|
+
Enable debug logging:
|
|
450
|
+
```bash
|
|
451
|
+
OTEL_LOG_LEVEL=debug npm run dev
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
You'll see:
|
|
455
|
+
```
|
|
456
|
+
[securenow] 📝 Request body capture: ENABLED (max: 10240 bytes, redacting 23 sensitive fields)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 🎉 Summary
|
|
462
|
+
|
|
463
|
+
**Redaction works on ALL content types:**
|
|
464
|
+
|
|
465
|
+
| Type | Redaction | Method |
|
|
466
|
+
|------|-----------|--------|
|
|
467
|
+
| **JSON** | ✅ Yes | Object property matching |
|
|
468
|
+
| **GraphQL** | ✅ Yes | Regex pattern matching |
|
|
469
|
+
| **Form Data** | ✅ Yes | Parsed then object matching |
|
|
470
|
+
| **Multipart** | ❌ N/A | Not captured at all |
|
|
471
|
+
|
|
472
|
+
**Protection:**
|
|
473
|
+
- 20+ built-in sensitive fields
|
|
474
|
+
- Custom fields support
|
|
475
|
+
- Case-insensitive matching
|
|
476
|
+
- Substring matching (e.g., "password" matches "user_password")
|
|
477
|
+
- Recursive (works at any nesting level)
|
|
478
|
+
- Fast (< 1ms overhead)
|
|
479
|
+
|
|
480
|
+
**Your data is safe!** 🔒
|
|
481
|
+
|