securenow 4.0.2 → 4.0.3
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/BODY-CAPTURE-QUICKSTART.md +147 -0
- package/CUSTOMER-GUIDE.md +19 -0
- package/NEXTJS-GUIDE.md +10 -0
- package/NEXTJS-QUICKSTART.md +1 -1
- package/REDACTION-EXAMPLES.md +481 -0
- package/REQUEST-BODY-CAPTURE.md +575 -0
- package/nextjs.js +229 -2
- package/package.json +5 -2
- package/tracing.js +154 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 📝 Request Body Capture - Quick Start
|
|
2
|
+
|
|
3
|
+
## Enable in 30 Seconds
|
|
4
|
+
|
|
5
|
+
### Step 1: Enable
|
|
6
|
+
Add to `.env.local`:
|
|
7
|
+
```bash
|
|
8
|
+
SECURENOW_CAPTURE_BODY=1
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Step 2: Deploy
|
|
12
|
+
```bash
|
|
13
|
+
npm run dev # or deploy to production
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Step 3: Done! ✅
|
|
17
|
+
|
|
18
|
+
All POST/PUT/PATCH request bodies are now captured with sensitive data automatically redacted!
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## What Gets Captured (ALL with Auto-Redaction!)
|
|
23
|
+
|
|
24
|
+
✅ **JSON** - API payloads (objects redacted)
|
|
25
|
+
✅ **GraphQL** - Queries and mutations (arguments/variables redacted)
|
|
26
|
+
✅ **Form Data** - Form submissions (parsed and redacted)
|
|
27
|
+
❌ **File Uploads** - NOT captured at all (by design)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Security Built-In
|
|
32
|
+
|
|
33
|
+
These fields are **automatically redacted**:
|
|
34
|
+
- `password`, `token`, `api_key`, `secret`
|
|
35
|
+
- `access_token`, `auth`, `credentials`
|
|
36
|
+
- `card`, `cardnumber`, `cvv`, `ssn`
|
|
37
|
+
- And 15+ more sensitive fields
|
|
38
|
+
|
|
39
|
+
**Example:**
|
|
40
|
+
```json
|
|
41
|
+
// Original
|
|
42
|
+
{"username": "john", "password": "secret123"}
|
|
43
|
+
|
|
44
|
+
// Captured
|
|
45
|
+
{"username": "john", "password": "[REDACTED]"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Configuration Options
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Enable capture (required)
|
|
54
|
+
SECURENOW_CAPTURE_BODY=1
|
|
55
|
+
|
|
56
|
+
# Max body size in bytes (default: 10KB)
|
|
57
|
+
SECURENOW_MAX_BODY_SIZE=20480
|
|
58
|
+
|
|
59
|
+
# Add custom sensitive fields to redact
|
|
60
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone,address
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## View in SigNoz
|
|
66
|
+
|
|
67
|
+
Query for captured bodies:
|
|
68
|
+
```
|
|
69
|
+
http.request.body IS NOT NULL
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
See specific endpoint:
|
|
73
|
+
```
|
|
74
|
+
http.target = "/api/checkout"
|
|
75
|
+
AND http.request.body CONTAINS "product"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Examples
|
|
81
|
+
|
|
82
|
+
### Next.js API Route
|
|
83
|
+
```typescript
|
|
84
|
+
// app/api/login/route.ts
|
|
85
|
+
export async function POST(request: Request) {
|
|
86
|
+
const body = await request.json();
|
|
87
|
+
// Body automatically captured in traces!
|
|
88
|
+
return Response.json({ success: true });
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Express.js
|
|
93
|
+
```javascript
|
|
94
|
+
app.post('/api/login', (req, res) => {
|
|
95
|
+
// req.body automatically captured!
|
|
96
|
+
res.json({ success: true });
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Safety Features
|
|
103
|
+
|
|
104
|
+
✅ **Size limits** - Bodies over limit show `[TOO LARGE]`
|
|
105
|
+
✅ **Auto-redaction** - 20+ sensitive fields protected
|
|
106
|
+
✅ **Type detection** - JSON, GraphQL, Form parsed correctly
|
|
107
|
+
✅ **No file capture** - Multipart uploads excluded
|
|
108
|
+
✅ **Fast** - < 1ms overhead per request
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Common Use Cases
|
|
113
|
+
|
|
114
|
+
1. **Debug API errors** - See exact input that caused error
|
|
115
|
+
2. **Monitor GraphQL** - Track slow queries
|
|
116
|
+
3. **Validate inputs** - Understand user input patterns
|
|
117
|
+
4. **Track features** - See which API features are used
|
|
118
|
+
5. **Security analysis** - Detect malicious payloads
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Privacy Notes
|
|
123
|
+
|
|
124
|
+
⚠️ Request bodies may contain personal data
|
|
125
|
+
|
|
126
|
+
**Best practices:**
|
|
127
|
+
- Add relevant fields to `SECURENOW_SENSITIVE_FIELDS`
|
|
128
|
+
- Set appropriate retention in SigNoz
|
|
129
|
+
- Document in privacy policy
|
|
130
|
+
- Consider GDPR/CCPA requirements
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Full Documentation
|
|
135
|
+
|
|
136
|
+
See [REQUEST-BODY-CAPTURE.md](./REQUEST-BODY-CAPTURE.md) for:
|
|
137
|
+
- Complete security guide
|
|
138
|
+
- GDPR compliance tips
|
|
139
|
+
- Advanced configuration
|
|
140
|
+
- Performance optimization
|
|
141
|
+
- Troubleshooting
|
|
142
|
+
- FAQ
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
**That's it!** Enable with one environment variable, get full request visibility with automatic security. 🔒
|
|
147
|
+
|
package/CUSTOMER-GUIDE.md
CHANGED
|
@@ -125,6 +125,25 @@ Open your **SigNoz dashboard** and you'll see traces immediately!
|
|
|
125
125
|
- Performance analysis by region
|
|
126
126
|
- Marketing attribution
|
|
127
127
|
|
|
128
|
+
### 📝 Request Body Capture (Optional - Enable It!)
|
|
129
|
+
- **JSON Payloads** - Capture API request bodies
|
|
130
|
+
- **GraphQL Queries** - See full queries in traces
|
|
131
|
+
- **Form Submissions** - Track form data
|
|
132
|
+
- **Auto-Redaction** - Passwords, tokens, cards automatically hidden
|
|
133
|
+
- **Size Limits** - Configurable max body size
|
|
134
|
+
- **GDPR-Friendly** - Built-in sensitive field protection
|
|
135
|
+
|
|
136
|
+
**Enable:** `SECURENOW_CAPTURE_BODY=1` in `.env.local`
|
|
137
|
+
|
|
138
|
+
**Perfect for:**
|
|
139
|
+
- Debugging API issues with exact inputs
|
|
140
|
+
- Monitoring GraphQL query patterns
|
|
141
|
+
- Understanding user input behavior
|
|
142
|
+
- Validating request schemas
|
|
143
|
+
- Troubleshooting edge cases
|
|
144
|
+
|
|
145
|
+
See [REQUEST-BODY-CAPTURE.md](./REQUEST-BODY-CAPTURE.md)
|
|
146
|
+
|
|
128
147
|
### ✅ Next.js Built-in Spans
|
|
129
148
|
- HTTP requests
|
|
130
149
|
- API routes
|
package/NEXTJS-GUIDE.md
CHANGED
|
@@ -113,6 +113,16 @@ SecureNow automatically captures comprehensive request data:
|
|
|
113
113
|
|
|
114
114
|
See [AUTOMATIC-IP-CAPTURE.md](./AUTOMATIC-IP-CAPTURE.md) for full details.
|
|
115
115
|
|
|
116
|
+
### 📝 Request Body Capture (Optional!)
|
|
117
|
+
- **JSON Bodies** - API payloads with sensitive fields redacted
|
|
118
|
+
- **GraphQL Queries** - Full query capture
|
|
119
|
+
- **Form Data** - Form submissions
|
|
120
|
+
- **Auto-Redaction** - Passwords, tokens, cards automatically hidden
|
|
121
|
+
|
|
122
|
+
Enable with: `SECURENOW_CAPTURE_BODY=1`
|
|
123
|
+
|
|
124
|
+
See [REQUEST-BODY-CAPTURE.md](./REQUEST-BODY-CAPTURE.md) for full details.
|
|
125
|
+
|
|
116
126
|
### Next.js Built-in Spans
|
|
117
127
|
- ✅ HTTP requests (`[http.method] [next.route]`)
|
|
118
128
|
- ✅ API routes execution
|
package/NEXTJS-QUICKSTART.md
CHANGED
|
@@ -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
|
+
|