fix(security): per-mobile OTP cap + refresh-token rotation (M6, M7)
M6: send-code rate-limited only per IP, so a victim's number could be SMS-flooded from rotating IPs. Add a per-mobile bucket (same 5/hour policy) keyed by the validated mobile. M7: /oauth/token/refresh reused the presented refresh token verbatim (no rotation) and never re-checked the user. The rotation infra already existed (issueTokens mints a fresh refresh token) — the controller just discarded it. Now revoke the presented token (single-use), issue a fresh pair, and reject a suspended user (status != 1). Regressions: tests/Auth/SendCodeMobileRateLimitTest, tests/Auth/RefreshTokenRotationTest (both fail without the fix). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -38,6 +38,7 @@ Send OTP code to mobile number.
|
||||
|------|------|-------------|
|
||||
| `ERR_VALIDATION_001` | 422 | Invalid mobile format |
|
||||
| `ERR_AUTH_004` | 429 | OTP rate limit exceeded |
|
||||
| `ERR_RATE_LIMIT_001` | 429 | بیش از حد مجاز — هم per-IP (۵ در ۶۰ دقیقه) و هم **per-mobile** (۵ در ۶۰ دقیقه؛ ضد flood از IPهای چرخشی) |
|
||||
|
||||
---
|
||||
|
||||
@@ -219,18 +220,23 @@ Refresh expired JWT using refresh token.
|
||||
}
|
||||
```
|
||||
|
||||
> **چرخش (rotation):** هر refresh token **یکبارمصرف** است. با هر فراخوانی، توکن ارائهشده باطل میشود و یک جفت `access_token` + `refresh_token` تازه صادر میگردد. توکن قبلی دیگر کار نمیکند (`401`). کاربر **معلق** (`status != 1`) نمیتواند refresh کند.
|
||||
|
||||
### Response `200`
|
||||
```json
|
||||
{
|
||||
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
|
||||
"refresh_token": "def50200..."
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
|
||||
"refresh_token": "<توکن جدید — با قبلی فرق دارد>",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 900,
|
||||
"refresh_token_expires_in": 2592000
|
||||
}
|
||||
```
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
|------|------|-------------|
|
||||
| `ERR_AUTH_001` | 401 | Invalid or expired refresh token |
|
||||
| `ERR_AUTH_001` | 401 | Invalid/expired/already-rotated refresh token, or suspended user |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user