fix(security): resolve Security-001/002/003 — reachable StartTLS path, Secure cookie, JWT signing key validation
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
| Last reviewed | 2026-05-16 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `9c60592` |
|
||||
| Open findings | 11 |
|
||||
| Open findings | 8 |
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -51,7 +51,7 @@ defects that should be fixed before any production deployment.
|
||||
|--|--|
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:37-47` |
|
||||
|
||||
**Description**
|
||||
@@ -74,7 +74,12 @@ session is encrypted before binding. Remove the unreachable conditional.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
Resolved 2026-05-16 (commit `<pending>`). Added an explicit `LdapTransport` enum
|
||||
(`Ldaps`/`StartTls`/`None`); `SecureSocketLayer` is set only for LDAPS, and the
|
||||
StartTLS branch now connects in plaintext, calls `StartTls()`, and verifies
|
||||
`connection.Tls` before binding. `LdapUseTls` is retained as a compatibility shim
|
||||
mapping onto the enum. Regression tests `AuthenticateAsync_StartTlsTransport_AttemptsConnection`
|
||||
and `AuthenticateAsync_NoTlsTransport_RejectedWithoutAllowInsecure`.
|
||||
|
||||
### Security-002 — Authentication cookie is not marked `Secure`
|
||||
|
||||
@@ -82,7 +87,7 @@ _Unresolved._
|
||||
|--|--|
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/ServiceCollectionExtensions.cs:16-23` |
|
||||
|
||||
**Description**
|
||||
@@ -102,7 +107,12 @@ the documented 15-minute JWT / 30-minute idle policy.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
Resolved 2026-05-16 (commit `<pending>`). Confirmed the cookie is configured in this
|
||||
module (`ServiceCollectionExtensions.AddSecurity`), not CentralUI — no misattribution.
|
||||
Added `options.Cookie.SecurePolicy = CookieSecurePolicy.Always` so the JWT-bearing
|
||||
cookie is never sent over plain HTTP. Regression test
|
||||
`AddSecurity_AuthCookie_IsMarkedSecureAlways`. (`ExpireTimeSpan`/`SlidingExpiration`
|
||||
tuning left as a separate, lower-priority improvement.)
|
||||
|
||||
### Security-003 — JWT signing key length is never validated
|
||||
|
||||
@@ -110,7 +120,7 @@ _Unresolved._
|
||||
|--|--|
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/JwtTokenService.cs:33`, `src/ScadaLink.Security/SecurityOptions.cs:42` |
|
||||
|
||||
**Description**
|
||||
@@ -131,7 +141,14 @@ constructor so a weak key is rejected before any token is issued.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
Resolved 2026-05-16 (commit `<pending>`). The `JwtTokenService` constructor now
|
||||
fails fast with an `InvalidOperationException` when `JwtSigningKey` is empty or
|
||||
shorter than 32 bytes (`SecurityOptions.MinJwtSigningKeyBytes`), so a weak key is
|
||||
rejected before any token is issued. The misleading `SecurityOptions` XML doc was
|
||||
corrected to state the requirement. Regression tests
|
||||
`JwtTokenService_EmptySigningKey_ThrowsAtConstruction`,
|
||||
`JwtTokenService_ShortSigningKey_ThrowsAtConstruction`, and
|
||||
`JwtTokenService_AdequateSigningKey_ConstructsSuccessfully`.
|
||||
|
||||
### Security-004 — Search filter uses `uid=` while fallback DN construction uses `cn=`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user