mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-06 18:12:00 +00:00
fix(api): sanitize request path in internal API key logs (SEC-29)
Strip CR/LF from Request.Path before logging invalid-key and disallowed-path warnings so CodeQL alerts 4 and 5 close without changing 401/403 behavior.
This commit is contained in:
parent
4cc550500a
commit
05d87b2e04
1 changed files with 29 additions and 3 deletions
|
|
@ -14,6 +14,27 @@ public class InternalApiKeyMiddleware
|
||||||
"/api/files",
|
"/api/files",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private static string SanitizeForLog(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sanitized = value.Replace("\r", "").Replace("\n", "");
|
||||||
|
var builder = new StringBuilder(sanitized.Length);
|
||||||
|
|
||||||
|
foreach (var c in sanitized)
|
||||||
|
{
|
||||||
|
if (!char.IsControl(c))
|
||||||
|
{
|
||||||
|
builder.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly byte[] _apiKeyBytes;
|
private readonly byte[] _apiKeyBytes;
|
||||||
private readonly ILogger<InternalApiKeyMiddleware> _logger;
|
private readonly ILogger<InternalApiKeyMiddleware> _logger;
|
||||||
|
|
@ -32,20 +53,25 @@ public class InternalApiKeyMiddleware
|
||||||
context.Request.Headers.TryGetValue("X-Internal-Api-Key", out var providedKey) &&
|
context.Request.Headers.TryGetValue("X-Internal-Api-Key", out var providedKey) &&
|
||||||
!string.IsNullOrEmpty(providedKey.ToString()))
|
!string.IsNullOrEmpty(providedKey.ToString()))
|
||||||
{
|
{
|
||||||
|
var path = context.Request.Path.Value ?? "";
|
||||||
|
var sanitizedPath = SanitizeForLog(path);
|
||||||
|
|
||||||
var providedBytes = Encoding.UTF8.GetBytes(providedKey.ToString());
|
var providedBytes = Encoding.UTF8.GetBytes(providedKey.ToString());
|
||||||
if (!CryptographicOperations.FixedTimeEquals(providedBytes, _apiKeyBytes))
|
if (!CryptographicOperations.FixedTimeEquals(providedBytes, _apiKeyBytes))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Invalid internal API key from {RemoteIp} on {Path}",
|
_logger.LogWarning("Invalid internal API key from {RemoteIp} on {Path}",
|
||||||
context.Connection.RemoteIpAddress, context.Request.Path);
|
context.Connection.RemoteIpAddress, sanitizedPathForLog);
|
||||||
context.Response.StatusCode = 401;
|
context.Response.StatusCode = 401;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = context.Request.Path.Value ?? "";
|
|
||||||
if (!AllowedPathPrefixes.Any(prefix => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
if (!AllowedPathPrefixes.Any(prefix => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
var sanitizedPathForLog = path
|
||||||
|
.Replace("\r", "")
|
||||||
|
.Replace("\n", "");
|
||||||
_logger.LogWarning("Internal API key used on disallowed path {Path} from {RemoteIp}",
|
_logger.LogWarning("Internal API key used on disallowed path {Path} from {RemoteIp}",
|
||||||
context.Request.Path, context.Connection.RemoteIpAddress);
|
sanitizedPathForLog, context.Connection.RemoteIpAddress);
|
||||||
context.Response.StatusCode = 403;
|
context.Response.StatusCode = 403;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue