@sun-asterisk/sunlint 1.3.18 → 1.3.19
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 +2 -1
- package/core/github-annotate-service.js +89 -0
- package/core/output-service.js +25 -0
- package/core/summary-report-service.js +30 -30
- package/package.json +3 -2
- 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,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rule": {
|
|
3
|
+
"id": "S045",
|
|
4
|
+
"name": "Brute-force Protection",
|
|
5
|
+
"description": "Implement protection against brute-force attacks on authentication endpoints. This rule detects missing rate limiting, account lockout mechanisms, and other brute-force protection measures in authentication flows.",
|
|
6
|
+
"category": "security",
|
|
7
|
+
"severity": "error",
|
|
8
|
+
"languages": ["typescript", "javascript"],
|
|
9
|
+
"frameworks": ["nestjs", "express", "node"],
|
|
10
|
+
"version": "1.0.0",
|
|
11
|
+
"status": "stable",
|
|
12
|
+
"tags": ["security", "authentication", "brute-force", "rate-limiting", "owasp"],
|
|
13
|
+
"references": [
|
|
14
|
+
"https://owasp.org/www-community/attacks/Brute_force_attack",
|
|
15
|
+
"https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html",
|
|
16
|
+
"https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks",
|
|
17
|
+
"https://portswigger.net/web-security/authentication/password-based/brute-force"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"configuration": {
|
|
21
|
+
"enableRateLimitDetection": true,
|
|
22
|
+
"enableAccountLockoutDetection": true,
|
|
23
|
+
"enableCaptchaDetection": true,
|
|
24
|
+
"checkAuthenticationEndpoints": [
|
|
25
|
+
"login",
|
|
26
|
+
"signin",
|
|
27
|
+
"authenticate",
|
|
28
|
+
"auth",
|
|
29
|
+
"password",
|
|
30
|
+
"reset",
|
|
31
|
+
"forgot"
|
|
32
|
+
],
|
|
33
|
+
"rateLimitLibraries": [
|
|
34
|
+
"express-rate-limit",
|
|
35
|
+
"express-slow-down",
|
|
36
|
+
"@nestjs/throttler",
|
|
37
|
+
"rate-limiter-flexible",
|
|
38
|
+
"bottleneck",
|
|
39
|
+
"limiter"
|
|
40
|
+
],
|
|
41
|
+
"accountLockoutLibraries": [
|
|
42
|
+
"express-slow-down",
|
|
43
|
+
"rate-limiter-flexible",
|
|
44
|
+
"express-brute",
|
|
45
|
+
"express-brute-mongo"
|
|
46
|
+
],
|
|
47
|
+
"captchaLibraries": [
|
|
48
|
+
"recaptcha",
|
|
49
|
+
"hcaptcha",
|
|
50
|
+
"turnstile",
|
|
51
|
+
"captcha"
|
|
52
|
+
],
|
|
53
|
+
"vulnerablePatterns": [
|
|
54
|
+
"login.*without.*rate.*limit",
|
|
55
|
+
"auth.*without.*throttle",
|
|
56
|
+
"password.*without.*lockout",
|
|
57
|
+
"signin.*without.*captcha"
|
|
58
|
+
],
|
|
59
|
+
"protectionPatterns": [
|
|
60
|
+
"rate.*limit",
|
|
61
|
+
"throttle",
|
|
62
|
+
"lockout",
|
|
63
|
+
"captcha",
|
|
64
|
+
"brute.*force.*protection",
|
|
65
|
+
"max.*attempts",
|
|
66
|
+
"cooldown"
|
|
67
|
+
],
|
|
68
|
+
"maxAttemptsThreshold": 5,
|
|
69
|
+
"timeWindowMinutes": 15
|
|
70
|
+
},
|
|
71
|
+
"examples": {
|
|
72
|
+
"violations": [
|
|
73
|
+
{
|
|
74
|
+
"description": "Login endpoint without rate limiting",
|
|
75
|
+
"code": "@Post('login')\nasync login(@Body() loginDto: LoginDto) {\n return this.authService.validateUser(loginDto);\n}"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"description": "Authentication without account lockout",
|
|
79
|
+
"code": "app.post('/auth/login', (req, res) => {\n const { username, password } = req.body;\n // No rate limiting or lockout mechanism\n authenticateUser(username, password);\n});"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"description": "Password reset without protection",
|
|
83
|
+
"code": "@Post('reset-password')\nasync resetPassword(@Body() resetDto: ResetPasswordDto) {\n // No rate limiting or captcha\n return this.authService.resetPassword(resetDto);\n}"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"fixes": [
|
|
87
|
+
{
|
|
88
|
+
"description": "Login with rate limiting and account lockout",
|
|
89
|
+
"code": "@Post('login')\n@Throttle(5, 60) // 5 attempts per minute\nasync login(@Body() loginDto: LoginDto) {\n return this.authService.validateUser(loginDto);\n}"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"description": "Express with rate limiting middleware",
|
|
93
|
+
"code": "const rateLimit = require('express-rate-limit');\n\nconst loginLimiter = rateLimit({\n windowMs: 15 * 60 * 1000, // 15 minutes\n max: 5, // limit each IP to 5 requests per windowMs\n message: 'Too many login attempts'\n});\n\napp.post('/auth/login', loginLimiter, (req, res) => {\n // authentication logic\n});"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"description": "NestJS with ThrottlerModule",
|
|
97
|
+
"code": "@Module({\n imports: [\n ThrottlerModule.forRoot([{\n ttl: 60000,\n limit: 5,\n }]),\n ],\n})\nexport class AuthModule {}"
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
"testing": {
|
|
102
|
+
"testCases": [
|
|
103
|
+
{
|
|
104
|
+
"name": "login_without_rate_limit",
|
|
105
|
+
"type": "violation",
|
|
106
|
+
"description": "Login endpoint without rate limiting"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "auth_without_throttle",
|
|
110
|
+
"type": "violation",
|
|
111
|
+
"description": "Authentication without throttling"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"name": "password_reset_unprotected",
|
|
115
|
+
"type": "violation",
|
|
116
|
+
"description": "Password reset without protection"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "login_with_rate_limit",
|
|
120
|
+
"type": "clean",
|
|
121
|
+
"description": "Login with proper rate limiting"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "auth_with_throttle",
|
|
125
|
+
"type": "clean",
|
|
126
|
+
"description": "Authentication with throttling"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "password_reset_protected",
|
|
130
|
+
"type": "clean",
|
|
131
|
+
"description": "Password reset with protection"
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
"performance": {
|
|
136
|
+
"complexity": "O(n)",
|
|
137
|
+
"description": "Linear complexity based on number of authentication endpoints and middleware usage"
|
|
138
|
+
}
|
|
139
|
+
}
|