@sun-asterisk/sunlint 1.3.16 → 1.3.17
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/rule-analysis-strategies.js +3 -3
- package/config/rules/enhanced-rules-registry.json +40 -20
- package/core/cli-action-handler.js +2 -2
- package/core/config-merger.js +28 -6
- package/core/constants/defaults.js +1 -1
- package/core/file-targeting-service.js +72 -4
- package/core/output-service.js +21 -4
- package/engines/heuristic-engine.js +5 -0
- package/package.json +1 -1
- package/rules/common/C002_no_duplicate_code/README.md +115 -0
- package/rules/common/C002_no_duplicate_code/analyzer.js +615 -219
- package/rules/common/C002_no_duplicate_code/test-cases/api-handlers.ts +64 -0
- package/rules/common/C002_no_duplicate_code/test-cases/data-processor.ts +46 -0
- package/rules/common/C002_no_duplicate_code/test-cases/good-example.tsx +40 -0
- package/rules/common/C002_no_duplicate_code/test-cases/product-service.ts +57 -0
- package/rules/common/C002_no_duplicate_code/test-cases/user-service.ts +49 -0
- package/rules/common/C008/analyzer.js +40 -0
- package/rules/common/C008/config.json +20 -0
- package/rules/common/C008/ts-morph-analyzer.js +1067 -0
- package/rules/common/C018_no_throw_generic_error/analyzer.js +1 -1
- package/rules/common/C018_no_throw_generic_error/symbol-based-analyzer.js +27 -3
- package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +504 -162
- package/rules/common/C029_catch_block_logging/analyzer.js +499 -89
- package/rules/common/C033_separate_service_repository/README.md +131 -20
- package/rules/common/C033_separate_service_repository/analyzer.js +1 -1
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +417 -274
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +144 -254
- package/rules/common/C041_no_sensitive_hardcode/config.json +50 -0
- package/rules/common/C041_no_sensitive_hardcode/symbol-based-analyzer.js +575 -0
- package/rules/common/C067_no_hardcoded_config/analyzer.js +17 -16
- package/rules/common/C067_no_hardcoded_config/symbol-based-analyzer.js +3477 -659
- package/rules/docs/C002_no_duplicate_code.md +276 -11
- package/rules/index.js +5 -1
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +266 -88
- package/rules/security/S006_no_plaintext_recovery_codes/symbol-based-analyzer.js +805 -0
- package/rules/security/S010_no_insecure_encryption/README.md +78 -0
- package/rules/security/S010_no_insecure_encryption/analyzer.js +463 -398
- package/rules/security/S013_tls_enforcement/README.md +51 -0
- package/rules/security/S013_tls_enforcement/analyzer.js +99 -0
- package/rules/security/S013_tls_enforcement/config.json +41 -0
- package/rules/security/S013_tls_enforcement/symbol-based-analyzer.js +339 -0
- package/rules/security/S014_tls_version_enforcement/README.md +354 -0
- package/rules/security/S014_tls_version_enforcement/analyzer.js +118 -0
- package/rules/security/S014_tls_version_enforcement/config.json +56 -0
- package/rules/security/S014_tls_version_enforcement/symbol-based-analyzer.js +194 -0
- package/rules/security/S055_content_type_validation/analyzer.js +121 -279
- package/rules/security/S055_content_type_validation/symbol-based-analyzer.js +346 -0
- package/rules/tests/C002_no_duplicate_code.test.js +111 -22
- package/rules/common/C029_catch_block_logging/analyzer-smart-pipeline.js +0 -755
- package/rules/common/C041_no_sensitive_hardcode/ast-analyzer.js +0 -296
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
# S010 - Must use cryptographically secure random number generators (CSPRNG)
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
+
|
|
4
5
|
Quy tắc này phát hiện việc sử dụng các hàm tạo số ngẫu nhiên không an toàn (như `Math.random()`) cho các mục đích bảo mật, có thể dẫn đến các lỗ hổng bảo mật nghiêm trọng do tính có thể dự đoán được.
|
|
5
6
|
|
|
7
|
+
**Analyzer Version**: 2.0 (AST-based with ts-morph) - Context-aware detection with minimal false positives
|
|
8
|
+
|
|
6
9
|
## OWASP Classification
|
|
10
|
+
|
|
7
11
|
- **Category**: A02:2021 - Cryptographic Failures
|
|
8
12
|
- **CWE**: CWE-338 - Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
|
|
9
13
|
- **Severity**: Error
|
|
10
14
|
- **Impact**: High (Predictable tokens, weak encryption keys, authentication bypass)
|
|
11
15
|
|
|
12
16
|
## Vấn đề
|
|
17
|
+
|
|
13
18
|
Khi sử dụng các hàm tạo số ngẫu nhiên không an toàn cho mục đích bảo mật:
|
|
14
19
|
|
|
15
20
|
1. **Tính dự đoán**: `Math.random()` và các hàm tương tự có thể được dự đoán bởi kẻ tấn công
|
|
@@ -20,6 +25,7 @@ Khi sử dụng các hàm tạo số ngẫu nhiên không an toàn cho mục đ
|
|
|
20
25
|
## Các trường hợp vi phạm
|
|
21
26
|
|
|
22
27
|
### 1. Sử dụng Math.random() cho security tokens
|
|
28
|
+
|
|
23
29
|
```javascript
|
|
24
30
|
// ❌ Vi phạm - Math.random() không an toàn cho security
|
|
25
31
|
const sessionToken = Math.random().toString(36).substring(2);
|
|
@@ -37,6 +43,7 @@ const jwtSecret = Math.random().toString(36);
|
|
|
37
43
|
```
|
|
38
44
|
|
|
39
45
|
### 2. Sử dụng timestamp cho random generation
|
|
46
|
+
|
|
40
47
|
```javascript
|
|
41
48
|
// ❌ Vi phạm - timestamp có thể dự đoán được
|
|
42
49
|
const userId = Date.now().toString();
|
|
@@ -48,6 +55,7 @@ const token = Date.now() + '-' + Math.random().toString(36);
|
|
|
48
55
|
```
|
|
49
56
|
|
|
50
57
|
### 3. Sử dụng cho mã hóa và authentication
|
|
58
|
+
|
|
51
59
|
```javascript
|
|
52
60
|
// ❌ Vi phạm - tạo encryption key không an toàn
|
|
53
61
|
const encryptionKey = Math.random().toString(36).repeat(3);
|
|
@@ -61,6 +69,7 @@ const csrfToken = Math.floor(Math.random() * 1000000000);
|
|
|
61
69
|
```
|
|
62
70
|
|
|
63
71
|
### 4. Tạo unique identifiers không an toàn
|
|
72
|
+
|
|
64
73
|
```javascript
|
|
65
74
|
// ❌ Vi phạm - tạo user ID
|
|
66
75
|
const generateUserId = () => Math.random().toString(36).substring(2);
|
|
@@ -75,6 +84,7 @@ const tempFile = `temp_${Date.now()}_${Math.random()}.tmp`;
|
|
|
75
84
|
## Giải pháp an toàn
|
|
76
85
|
|
|
77
86
|
### 1. Sử dụng crypto.randomBytes()
|
|
87
|
+
|
|
78
88
|
```javascript
|
|
79
89
|
// ✅ An toàn - sử dụng crypto.randomBytes()
|
|
80
90
|
const crypto = require('crypto');
|
|
@@ -85,6 +95,7 @@ const resetCode = crypto.randomBytes(3).toString('hex'); // 6 hex chars
|
|
|
85
95
|
```
|
|
86
96
|
|
|
87
97
|
### 2. Sử dụng crypto.randomUUID()
|
|
98
|
+
|
|
88
99
|
```javascript
|
|
89
100
|
// ✅ An toàn - sử dụng crypto.randomUUID()
|
|
90
101
|
const sessionId = crypto.randomUUID();
|
|
@@ -93,6 +104,7 @@ const requestId = crypto.randomUUID();
|
|
|
93
104
|
```
|
|
94
105
|
|
|
95
106
|
### 3. Sử dụng crypto.randomInt()
|
|
107
|
+
|
|
96
108
|
```javascript
|
|
97
109
|
// ✅ An toàn - sử dụng crypto.randomInt()
|
|
98
110
|
const otpCode = crypto.randomInt(100000, 999999); // 6-digit OTP
|
|
@@ -101,6 +113,7 @@ const challengeNumber = crypto.randomInt(1, 1000000);
|
|
|
101
113
|
```
|
|
102
114
|
|
|
103
115
|
### 4. Sử dụng cho mã hóa an toàn
|
|
116
|
+
|
|
104
117
|
```javascript
|
|
105
118
|
// ✅ An toàn - tạo encryption key
|
|
106
119
|
const encryptionKey = crypto.randomBytes(32); // 256-bit key
|
|
@@ -115,6 +128,7 @@ const cipher = crypto.createCipher('aes-256-cbc', key, iv);
|
|
|
115
128
|
```
|
|
116
129
|
|
|
117
130
|
### 5. Sử dụng thư viện an toàn
|
|
131
|
+
|
|
118
132
|
```javascript
|
|
119
133
|
// ✅ An toàn - sử dụng nanoid
|
|
120
134
|
const { nanoid } = require('nanoid');
|
|
@@ -130,6 +144,7 @@ const randomBytes = secureRandom(32, { type: 'Buffer' });
|
|
|
130
144
|
```
|
|
131
145
|
|
|
132
146
|
### 6. Express.js session security
|
|
147
|
+
|
|
133
148
|
```javascript
|
|
134
149
|
// ✅ An toàn - cấu hình Express session
|
|
135
150
|
const session = require('express-session');
|
|
@@ -148,6 +163,7 @@ app.use(session({
|
|
|
148
163
|
```
|
|
149
164
|
|
|
150
165
|
### 7. JWT token generation
|
|
166
|
+
|
|
151
167
|
```javascript
|
|
152
168
|
// ✅ An toàn - tạo JWT với secure secret
|
|
153
169
|
const jwtSecret = crypto.randomBytes(64).toString('hex');
|
|
@@ -215,10 +231,72 @@ const mockData = Array.from({length: 10}, () => ({
|
|
|
215
231
|
}));
|
|
216
232
|
```
|
|
217
233
|
|
|
234
|
+
## Analyzer v2.0 - AST-based Context Detection
|
|
235
|
+
|
|
236
|
+
### Cải tiến chính
|
|
237
|
+
|
|
238
|
+
Analyzer mới sử dụng **ts-morph** để phân tích AST (Abstract Syntax Tree), cho phép:
|
|
239
|
+
|
|
240
|
+
1. **Context-aware detection**: Phân biệt security context vs non-security context
|
|
241
|
+
2. **Security function detection**: Phát hiện generic variable names trong security functions
|
|
242
|
+
3. **Minimal false positives**: Không flag filename, timestamp, request ID, logging
|
|
243
|
+
|
|
244
|
+
### Security Context Detection
|
|
245
|
+
|
|
246
|
+
**Sẽ flag (Security contexts):**
|
|
247
|
+
|
|
248
|
+
```javascript
|
|
249
|
+
// ❌ Security variable names
|
|
250
|
+
const otp = Math.random() * 1000000;
|
|
251
|
+
const sessionToken = Date.now().toString(36);
|
|
252
|
+
const apiKey = Math.random().toString(36);
|
|
253
|
+
const resetToken = Math.random();
|
|
254
|
+
|
|
255
|
+
// ❌ Generic names trong security functions
|
|
256
|
+
function generateOTP() {
|
|
257
|
+
const random = Math.random() * 1000000; // ← Flagged!
|
|
258
|
+
return random;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Sẽ KHÔNG flag (Non-security contexts):**
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
// ✅ Filenames
|
|
266
|
+
const zipFileName = `customer_${Date.now()}.zip`;
|
|
267
|
+
const backupFile = `backup_${Date.now()}.sql`;
|
|
268
|
+
|
|
269
|
+
// ✅ Expiration time calculations
|
|
270
|
+
const expriedTime = new Date(Date.now() + TTL);
|
|
271
|
+
|
|
272
|
+
// ✅ Request tracking / Logging
|
|
273
|
+
const requestId = `req_${Date.now()}`;
|
|
274
|
+
const logId = Date.now().toString(36);
|
|
275
|
+
const traceId = `trace_${Date.now()}`;
|
|
276
|
+
|
|
277
|
+
// ✅ Temporary files
|
|
278
|
+
const tempFile = `/tmp/upload_${Date.now()}.tmp`;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Technical Details
|
|
282
|
+
|
|
283
|
+
- **Library**: ts-morph (TypeScript AST parser)
|
|
284
|
+
- **Detection method**: Variable name analysis + Function context analysis
|
|
285
|
+
- **Languages**: JavaScript, TypeScript (.js, .jsx, .ts, .tsx)
|
|
286
|
+
- **Security keywords**: otp, token, session, apikey, password, verify, reset, magic, secret, etc.
|
|
287
|
+
- **Non-security keywords**: filename, log, request, trace, expire, temp, backup, etc.
|
|
288
|
+
|
|
289
|
+
### Migration from v1.0
|
|
290
|
+
|
|
291
|
+
- **v1.0**: Regex-based, 79 patterns, 89% accuracy, false positives with timestamps/filenames
|
|
292
|
+
- **v2.0**: AST-based, context-aware, 95%+ accuracy, minimal false positives
|
|
293
|
+
- **Backward compatibility**: Legacy analyzer backed up as `analyzer-regex-legacy.js`
|
|
294
|
+
|
|
218
295
|
## Tài liệu tham khảo
|
|
219
296
|
|
|
220
297
|
- [OWASP A02:2021 - Cryptographic Failures](https://owasp.org/Top10/A02_2021-Cryptographic_Failures/)
|
|
221
298
|
- [CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator](https://cwe.mitre.org/data/definitions/338.html)
|
|
222
299
|
- [Node.js Crypto Documentation](https://nodejs.org/api/crypto.html)
|
|
223
300
|
- [NIST Guidelines for Random Number Generation](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
|
|
301
|
+
- [ts-morph Documentation](https://ts-morph.com/)
|
|
224
302
|
- [Secure Random Number Generation Best Practices](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html)
|