@sun-asterisk/sunlint 1.3.18 → 1.3.20
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/config/rules/enhanced-rules-registry.json +77 -18
- package/core/cli-program.js +9 -1
- package/core/github-annotate-service.js +986 -0
- package/core/output-service.js +294 -6
- package/core/summary-report-service.js +30 -30
- package/docs/GITHUB_ACTIONS_INTEGRATION.md +421 -0
- package/package.json +2 -1
- package/rules/common/C014_dependency_injection/symbol-based-analyzer.js +392 -280
- package/rules/common/C017_constructor_logic/analyzer.js +137 -503
- package/rules/common/C017_constructor_logic/config.json +50 -0
- package/rules/common/C017_constructor_logic/symbol-based-analyzer.js +463 -0
- package/rules/security/S006_no_plaintext_recovery_codes/symbol-based-analyzer.js +463 -21
- package/rules/security/S011_secure_guid_generation/README.md +255 -0
- package/rules/security/S011_secure_guid_generation/analyzer.js +135 -0
- package/rules/security/S011_secure_guid_generation/config.json +56 -0
- package/rules/security/S011_secure_guid_generation/symbol-based-analyzer.js +609 -0
- package/rules/security/S028_file_upload_size_limits/README.md +537 -0
- package/rules/security/S028_file_upload_size_limits/analyzer.js +202 -0
- package/rules/security/S028_file_upload_size_limits/config.json +186 -0
- package/rules/security/S028_file_upload_size_limits/symbol-based-analyzer.js +530 -0
- package/rules/security/S041_session_token_invalidation/README.md +303 -0
- package/rules/security/S041_session_token_invalidation/analyzer.js +242 -0
- package/rules/security/S041_session_token_invalidation/config.json +175 -0
- package/rules/security/S041_session_token_invalidation/regex-based-analyzer.js +411 -0
- package/rules/security/S041_session_token_invalidation/symbol-based-analyzer.js +674 -0
- package/rules/security/S044_re_authentication_required/README.md +136 -0
- package/rules/security/S044_re_authentication_required/analyzer.js +242 -0
- package/rules/security/S044_re_authentication_required/config.json +161 -0
- package/rules/security/S044_re_authentication_required/regex-based-analyzer.js +329 -0
- package/rules/security/S044_re_authentication_required/symbol-based-analyzer.js +537 -0
- package/rules/security/S045_brute_force_protection/README.md +345 -0
- package/rules/security/S045_brute_force_protection/analyzer.js +336 -0
- package/rules/security/S045_brute_force_protection/config.json +139 -0
- package/rules/security/S045_brute_force_protection/symbol-based-analyzer.js +646 -0
- package/rules/common/C017_constructor_logic/semantic-analyzer.js +0 -340
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# S011 - Secure GUID Generation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Quy tắc này phát hiện việc sử dụng các phương pháp yếu hoặc có thể dự đoán được để tạo GUIDs/UUIDs cho mục đích bảo mật. GUIDs dùng cho session tokens, API keys, reset tokens, hoặc các mục đích bảo mật khác phải được tạo theo chuẩn UUID v4 với CSPRNG (Cryptographically Secure Pseudo-Random Number Generator).
|
|
6
|
+
|
|
7
|
+
## OWASP Classification
|
|
8
|
+
|
|
9
|
+
- **Category**: A02:2021 - Cryptographic Failures
|
|
10
|
+
- **CWE**: CWE-338 - Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
|
|
11
|
+
- **Severity**: Error
|
|
12
|
+
- **Impact**: High (Session hijacking, token prediction, unauthorized access)
|
|
13
|
+
|
|
14
|
+
## Vấn đề
|
|
15
|
+
|
|
16
|
+
Khi sử dụng các phương pháp yếu để tạo GUIDs cho mục đích bảo mật:
|
|
17
|
+
|
|
18
|
+
1. **Dễ dự đoán**: Kẻ tấn công có thể dự đoán GUIDs tiếp theo
|
|
19
|
+
2. **Session hijacking**: Session tokens yếu có thể bị đoán và chiếm quyền
|
|
20
|
+
3. **Token collision**: Xác suất trùng lặp cao hơn với PRNG yếu
|
|
21
|
+
4. **Brute force attacks**: Tokens dễ bị tấn công brute force
|
|
22
|
+
|
|
23
|
+
## Các trường hợp vi phạm
|
|
24
|
+
|
|
25
|
+
### 1. Sử dụng Math.random()
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// ❌ Vi phạm - Math.random() không an toàn cho mục đích bảo mật
|
|
29
|
+
const sessionId = Math.random().toString(36).substring(2, 15);
|
|
30
|
+
const apiKey = Math.random().toString(36) + Math.random().toString(36);
|
|
31
|
+
const resetToken = `${Date.now()}-${Math.random()}`;
|
|
32
|
+
|
|
33
|
+
// ❌ Vi phạm - Timestamp-based không đủ random
|
|
34
|
+
const token = Date.now().toString(36);
|
|
35
|
+
const userId = new Date().getTime();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Sử dụng UUID v1 (time-based)
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// ❌ Vi phạm - UUID v1 sử dụng timestamp và MAC address
|
|
42
|
+
import { v1 as uuidv1 } from "uuid";
|
|
43
|
+
|
|
44
|
+
const sessionToken = uuidv1(); // Time-based, có thể dự đoán
|
|
45
|
+
const apiKey = uuidv1(); // Không an toàn cho security purposes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Custom GUID generation yếu
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// ❌ Vi phạm - Custom implementation không sử dụng CSPRNG
|
|
52
|
+
function generateGuid() {
|
|
53
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
|
54
|
+
const r = (Math.random() * 16) | 0; // Math.random() không an toàn
|
|
55
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
56
|
+
return v.toString(16);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const resetToken = generateGuid();
|
|
61
|
+
const sessionId = generateGuid();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 4. Sử dụng cho security-critical purposes
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
// ❌ Vi phạm - Weak GUID cho authentication
|
|
68
|
+
app.post("/login", (req, res) => {
|
|
69
|
+
const sessionToken = Math.random().toString(36);
|
|
70
|
+
req.session.token = sessionToken;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// ❌ Vi phạm - Weak GUID cho password reset
|
|
74
|
+
const resetToken = Date.now() + "-" + Math.random();
|
|
75
|
+
await sendPasswordResetEmail(user.email, resetToken);
|
|
76
|
+
|
|
77
|
+
// ❌ Vi phạm - Weak GUID cho API key
|
|
78
|
+
const apiKey = uuidv1(); // Time-based UUID
|
|
79
|
+
await saveApiKey(userId, apiKey);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Giải pháp an toàn
|
|
83
|
+
|
|
84
|
+
### 1. Sử dụng crypto.randomUUID() (Node.js 14.17+)
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// ✅ An toàn - crypto.randomUUID() sử dụng CSPRNG
|
|
88
|
+
import { randomUUID } from "crypto";
|
|
89
|
+
|
|
90
|
+
const sessionId = randomUUID();
|
|
91
|
+
const apiKey = randomUUID();
|
|
92
|
+
const resetToken = randomUUID();
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 2. Sử dụng uuid v4 library
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// ✅ An toàn - uuid v4 sử dụng CSPRNG
|
|
99
|
+
import { v4 as uuidv4 } from "uuid";
|
|
100
|
+
|
|
101
|
+
const sessionToken = uuidv4();
|
|
102
|
+
const apiKey = uuidv4();
|
|
103
|
+
const resetToken = uuidv4();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. Sử dụng crypto.randomBytes()
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// ✅ An toàn - crypto.randomBytes() cho custom implementation
|
|
110
|
+
import { randomBytes } from "crypto";
|
|
111
|
+
|
|
112
|
+
const sessionId = randomBytes(16).toString("hex");
|
|
113
|
+
const apiKey = randomBytes(32).toString("base64url");
|
|
114
|
+
const resetToken = randomBytes(48).toString("base64url");
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 4. Best practices cho security tokens
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// ✅ An toàn - Session management
|
|
121
|
+
import { randomUUID } from "crypto";
|
|
122
|
+
|
|
123
|
+
app.post("/login", async (req, res) => {
|
|
124
|
+
const sessionToken = randomUUID();
|
|
125
|
+
await redis.set(`session:${sessionToken}`, userId, "EX", 3600);
|
|
126
|
+
res.cookie("sessionId", sessionToken, { httpOnly: true, secure: true });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// ✅ An toàn - Password reset token
|
|
130
|
+
import { randomBytes } from "crypto";
|
|
131
|
+
|
|
132
|
+
async function generateResetToken() {
|
|
133
|
+
const token = randomBytes(32).toString("hex");
|
|
134
|
+
const hashedToken = await bcrypt.hash(token, 10);
|
|
135
|
+
await saveToDatabase({ token: hashedToken, expiresAt: Date.now() + 3600000 });
|
|
136
|
+
return token;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ✅ An toàn - API key generation
|
|
140
|
+
import { v4 as uuidv4 } from "uuid";
|
|
141
|
+
|
|
142
|
+
const apiKey = `sk_${uuidv4().replace(/-/g, "")}`;
|
|
143
|
+
const hashedKey = await bcrypt.hash(apiKey, 10);
|
|
144
|
+
await saveApiKey(userId, hashedKey);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Phương pháp phát hiện
|
|
148
|
+
|
|
149
|
+
Rule này sử dụng symbol-based analysis để phát hiện:
|
|
150
|
+
|
|
151
|
+
1. **Math.random() usage**: Detect `Math.random()` trong context tạo tokens/IDs
|
|
152
|
+
2. **Timestamp-based IDs**: Detect `Date.now()`, `new Date().getTime()` cho security purposes
|
|
153
|
+
3. **UUID v1 usage**: Detect `uuidv1()` hoặc `uuid.v1()` cho authentication/authorization
|
|
154
|
+
4. **Weak GUID patterns**: Detect custom implementations không sử dụng CSPRNG
|
|
155
|
+
5. **Variable naming context**: Phân tích tên biến như `sessionId`, `token`, `apiKey`, `resetToken`
|
|
156
|
+
|
|
157
|
+
### Detection patterns:
|
|
158
|
+
|
|
159
|
+
- Variable names: `session`, `token`, `api`, `key`, `reset`, `auth`, `secret`
|
|
160
|
+
- Unsafe methods: `Math.random()`, `Date.now()`, `getTime()`, `uuidv1()`
|
|
161
|
+
- Secure methods: `crypto.randomUUID()`, `crypto.randomBytes()`, `uuidv4()`
|
|
162
|
+
|
|
163
|
+
## Safe contexts (không báo lỗi)
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
// ✅ OK - Sử dụng Math.random() cho non-security purposes
|
|
167
|
+
const displayId = Math.random().toString(36); // UI display ID
|
|
168
|
+
const tempId = Date.now(); // Temporary client-side ID
|
|
169
|
+
const orderId = `ORD-${Date.now()}`; // Business identifier, not security token
|
|
170
|
+
|
|
171
|
+
// ✅ OK - UUID v1 cho non-security purposes
|
|
172
|
+
const recordId = uuidv1(); // Database record ID (không dùng cho authentication)
|
|
173
|
+
const traceId = uuidv1(); // Distributed tracing ID
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Cấu hình
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"S011": {
|
|
181
|
+
"enabled": true,
|
|
182
|
+
"severity": "error",
|
|
183
|
+
"excludePatterns": ["test/**", "**/*.test.js", "**/*.spec.js"],
|
|
184
|
+
"securityKeywords": [
|
|
185
|
+
"session",
|
|
186
|
+
"token",
|
|
187
|
+
"api",
|
|
188
|
+
"key",
|
|
189
|
+
"reset",
|
|
190
|
+
"auth",
|
|
191
|
+
"secret",
|
|
192
|
+
"credential"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Best Practices
|
|
199
|
+
|
|
200
|
+
1. **Luôn dùng CSPRNG**: Sử dụng `crypto.randomUUID()` hoặc `crypto.randomBytes()` cho security tokens
|
|
201
|
+
2. **UUID v4 only**: Chỉ sử dụng UUID v4 cho security purposes, tránh UUID v1
|
|
202
|
+
3. **Sufficient entropy**: Đảm bảo đủ entropy (ít nhất 128 bits cho tokens)
|
|
203
|
+
4. **No predictable patterns**: Tránh patterns có thể dự đoán (timestamp, sequential IDs)
|
|
204
|
+
5. **Token expiration**: Luôn set thời hạn cho security tokens
|
|
205
|
+
6. **Hash before storage**: Hash tokens trước khi lưu vào database
|
|
206
|
+
|
|
207
|
+
## Platform-specific implementations
|
|
208
|
+
|
|
209
|
+
### Node.js
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
import { randomUUID, randomBytes } from "crypto";
|
|
213
|
+
const token = randomUUID(); // UUID v4 với CSPRNG
|
|
214
|
+
const key = randomBytes(32).toString("hex");
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Python
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
import secrets
|
|
221
|
+
import uuid
|
|
222
|
+
|
|
223
|
+
token = str(uuid.uuid4()) # UUID v4 với CSPRNG
|
|
224
|
+
key = secrets.token_urlsafe(32) # Secure random token
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Java
|
|
228
|
+
|
|
229
|
+
```java
|
|
230
|
+
import java.security.SecureRandom;
|
|
231
|
+
import java.util.UUID;
|
|
232
|
+
|
|
233
|
+
UUID token = UUID.randomUUID(); // UUID v4 với CSPRNG
|
|
234
|
+
SecureRandom random = new SecureRandom();
|
|
235
|
+
byte[] bytes = new byte[32];
|
|
236
|
+
random.nextBytes(bytes);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### .NET/C#
|
|
240
|
+
|
|
241
|
+
```csharp
|
|
242
|
+
using System;
|
|
243
|
+
using System.Security.Cryptography;
|
|
244
|
+
|
|
245
|
+
var token = Guid.NewGuid(); // GUID với CSPRNG
|
|
246
|
+
var bytes = RandomNumberGenerator.GetBytes(32); // Secure random
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Tài liệu tham khảo
|
|
250
|
+
|
|
251
|
+
- [OWASP A02:2021 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/)
|
|
252
|
+
- [CWE-338: Use of Cryptographically Weak PRNG](https://cwe.mitre.org/data/definitions/338.html)
|
|
253
|
+
- [RFC 4122: UUID Standard](https://www.rfc-editor.org/rfc/rfc4122)
|
|
254
|
+
- [Node.js Crypto Documentation](https://nodejs.org/api/crypto.html)
|
|
255
|
+
- [NIST SP 800-90A: Random Number Generation](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S011 - Secure GUID Generation
|
|
3
|
+
*
|
|
4
|
+
* Main analyzer using symbol-based analysis to detect weak GUID/UUID generation
|
|
5
|
+
* for security purposes.
|
|
6
|
+
*
|
|
7
|
+
* Based on:
|
|
8
|
+
* - OWASP A02:2021 - Cryptographic Failures
|
|
9
|
+
* - CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Command: node cli.js --rule=S011 --input=examples/rule-test-fixtures/rules/S011_secure_guid_generation --engine=heuristic
|
|
13
|
+
|
|
14
|
+
const S011SymbolBasedAnalyzer = require("./symbol-based-analyzer");
|
|
15
|
+
|
|
16
|
+
class S011Analyzer {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.ruleId = "S011";
|
|
19
|
+
this.semanticEngine = options.semanticEngine || null;
|
|
20
|
+
this.verbose = options.verbose || false;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
this.symbolAnalyzer = new S011SymbolBasedAnalyzer(this.semanticEngine);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.warn(`⚠ [S011] Failed to create symbol analyzer: ${e.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async initialize(semanticEngine) {
|
|
30
|
+
this.semanticEngine = semanticEngine;
|
|
31
|
+
if (this.symbolAnalyzer && this.symbolAnalyzer.initialize) {
|
|
32
|
+
await this.symbolAnalyzer.initialize(semanticEngine);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
analyzeSingle(filePath, options = {}) {
|
|
37
|
+
return this.analyze([filePath], "typescript", options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async analyze(files, language, options = {}) {
|
|
41
|
+
const violations = [];
|
|
42
|
+
for (const filePath of files) {
|
|
43
|
+
try {
|
|
44
|
+
const vs = await this.analyzeFile(filePath, options);
|
|
45
|
+
violations.push(...vs);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.warn(`⚠ [S011] Analysis error for ${filePath}: ${e.message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return violations;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async analyzeFile(filePath, options = {}) {
|
|
54
|
+
const violationMap = new Map();
|
|
55
|
+
|
|
56
|
+
if (!this.symbolAnalyzer) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Skip test files, build directories, and node_modules
|
|
61
|
+
if (this.shouldSkipFile(filePath)) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
let sourceFile = null;
|
|
67
|
+
if (this.semanticEngine?.project) {
|
|
68
|
+
sourceFile = this.semanticEngine.project.getSourceFile(filePath);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!sourceFile) {
|
|
72
|
+
// Create temporary ts-morph source file
|
|
73
|
+
const fs = require("fs");
|
|
74
|
+
const path = require("path");
|
|
75
|
+
const { Project } = require("ts-morph");
|
|
76
|
+
if (!fs.existsSync(filePath)) {
|
|
77
|
+
throw new Error(`File not found: ${filePath}`);
|
|
78
|
+
}
|
|
79
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
80
|
+
const tmp = new Project({
|
|
81
|
+
useInMemoryFileSystem: true,
|
|
82
|
+
compilerOptions: { allowJs: true },
|
|
83
|
+
});
|
|
84
|
+
sourceFile = tmp.createSourceFile(path.basename(filePath), content);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (sourceFile) {
|
|
88
|
+
const symbolViolations = await this.symbolAnalyzer.analyze(
|
|
89
|
+
sourceFile,
|
|
90
|
+
filePath
|
|
91
|
+
);
|
|
92
|
+
symbolViolations.forEach((v) => {
|
|
93
|
+
const key = `${v.line}:${v.column}:${v.message}`;
|
|
94
|
+
if (!violationMap.has(key)) violationMap.set(key, v);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
console.warn(`⚠ [S011] Symbol analysis failed: ${e.message}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return Array.from(violationMap.values()).map((v) => ({
|
|
102
|
+
...v,
|
|
103
|
+
filePath,
|
|
104
|
+
file: filePath,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
shouldSkipFile(filePath) {
|
|
109
|
+
const skipPatterns = [
|
|
110
|
+
"test/",
|
|
111
|
+
"tests/",
|
|
112
|
+
"__tests__/",
|
|
113
|
+
".test.",
|
|
114
|
+
".spec.",
|
|
115
|
+
"node_modules/",
|
|
116
|
+
"build/",
|
|
117
|
+
"dist/",
|
|
118
|
+
".next/",
|
|
119
|
+
"coverage/",
|
|
120
|
+
"vendor/",
|
|
121
|
+
"mocks/",
|
|
122
|
+
".mock.",
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
return skipPatterns.some((pattern) => filePath.includes(pattern));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
cleanup() {
|
|
129
|
+
if (this.symbolAnalyzer?.cleanup) {
|
|
130
|
+
this.symbolAnalyzer.cleanup();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = S011Analyzer;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ruleId": "S011",
|
|
3
|
+
"name": "Secure GUID Generation",
|
|
4
|
+
"description": "GUIDs used for security purposes must be generated according to UUID v4 standard with CSPRNG",
|
|
5
|
+
"category": "security",
|
|
6
|
+
"severity": "error",
|
|
7
|
+
"languages": ["All languages"],
|
|
8
|
+
"tags": [
|
|
9
|
+
"security",
|
|
10
|
+
"owasp",
|
|
11
|
+
"cryptographic-failures",
|
|
12
|
+
"uuid",
|
|
13
|
+
"guid",
|
|
14
|
+
"randomness"
|
|
15
|
+
],
|
|
16
|
+
"enabled": true,
|
|
17
|
+
"fixable": false,
|
|
18
|
+
"engine": "heuristic",
|
|
19
|
+
"metadata": {
|
|
20
|
+
"owaspCategory": "A02:2021 - Cryptographic Failures",
|
|
21
|
+
"cweId": "CWE-338",
|
|
22
|
+
"description": "Using weak or predictable methods to generate GUIDs/UUIDs for security purposes (session tokens, API keys, reset tokens) can lead to security vulnerabilities. Security-critical GUIDs must be generated using UUID v4 with Cryptographically Secure Pseudo-Random Number Generator (CSPRNG).",
|
|
23
|
+
"impact": "High - Session hijacking, token prediction, unauthorized access",
|
|
24
|
+
"likelihood": "Medium",
|
|
25
|
+
"remediation": "Use UUID v4 with CSPRNG libraries: crypto.randomUUID() (Node.js 14.17+), uuid v4, or equivalent secure random generators"
|
|
26
|
+
},
|
|
27
|
+
"patterns": {
|
|
28
|
+
"vulnerable": [
|
|
29
|
+
"Using Math.random() for GUID generation",
|
|
30
|
+
"Using Date.now() or timestamp-based GUIDs for security tokens",
|
|
31
|
+
"Using non-cryptographic UUID libraries",
|
|
32
|
+
"Using UUID v1 (time-based) for security purposes",
|
|
33
|
+
"Custom GUID generation without CSPRNG"
|
|
34
|
+
],
|
|
35
|
+
"secure": [
|
|
36
|
+
"crypto.randomUUID() for Node.js 14.17+",
|
|
37
|
+
"uuid v4 library with proper CSPRNG",
|
|
38
|
+
"crypto.randomBytes() for custom implementation",
|
|
39
|
+
"Platform-specific secure random: SecureRandom (Java), secrets (Python)"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"examples": {
|
|
43
|
+
"violations": [
|
|
44
|
+
"const sessionId = Math.random().toString(36);",
|
|
45
|
+
"const token = Date.now() + '-' + Math.random();",
|
|
46
|
+
"const apiKey = uuidv1(); // Time-based UUID",
|
|
47
|
+
"const resetToken = generateGuid(); // Custom weak implementation"
|
|
48
|
+
],
|
|
49
|
+
"fixes": [
|
|
50
|
+
"const sessionId = crypto.randomUUID();",
|
|
51
|
+
"const token = require('uuid').v4();",
|
|
52
|
+
"const apiKey = crypto.randomBytes(32).toString('hex');",
|
|
53
|
+
"const resetToken = crypto.randomUUID();"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|