websocket POC demo - not production ready.#844
websocket POC demo - not production ready.#844devinleighsmith wants to merge 1 commit intomasterfrom
Conversation
|
|
|
||
| logger?.LogInformation( | ||
| "SignalR connect attempt. Origin={Origin}, CORS_DOMAIN={CorsDomain}", | ||
| origin, |
Check failure
Code scanning / CodeQL
Log entries created from user input High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 days ago
In general, to fix log forging when logging user input, ensure the values are normalized or encoded before being passed to the logger. For plain-text logs, the minimal safe step is to remove or replace newline and carriage-return characters (and optionally other control characters) so that a malicious value cannot break log structure or inject fake entries.
Here, we should avoid changing functionality, so we will keep the same logging messages and behavior but sanitize origin before it is first used. Because origin is also used in the later warning (origin mismatch), the safest place is immediately after it is read from the header: create a sanitized version that strips \r and \n, and use that sanitized value in all logging calls, while keeping the original header value for any non-logging logic (if needed). In this snippet, origin is only used for comparisons and logging; stripping newlines will not affect equality checks for valid origins, because valid origins should not contain such characters.
Concretely, in api/Hubs/NotificationsHub.cs:
- After line 23 where
originis read, introduce a new variablesanitizedOriginthat removes newline characters fromorigin. - Use
sanitizedOrigininstead oforiginin the two logging calls that include the origin (lines 25–28 and 50–52). - No new external dependencies are required;
string.Replaceand the null-conditional operator are sufficient.
| @@ -21,10 +21,11 @@ | ||
| var allowedOrigin = config?.GetValue<string>("CORS_DOMAIN"); | ||
| var disableOriginCheck = config?.GetValue<bool>("DISABLE_SIGNALR_ORIGIN_CHECK") ?? false; | ||
| var origin = httpContext?.Request.Headers["Origin"].ToString(); | ||
| var sanitizedOrigin = origin?.Replace("\r", string.Empty).Replace("\n", string.Empty); | ||
|
|
||
| logger?.LogInformation( | ||
| "SignalR connect attempt. Origin={Origin}, CORS_DOMAIN={CorsDomain}", | ||
| origin, | ||
| sanitizedOrigin, | ||
| allowedOrigin); | ||
|
|
||
| if (disableOriginCheck) | ||
| @@ -49,7 +47,7 @@ | ||
| { | ||
| logger?.LogWarning( | ||
| "SignalR connection aborted due to origin mismatch. Origin={Origin}", | ||
| origin); | ||
| sanitizedOrigin); | ||
| Context.Abort(); | ||
| return Task.CompletedTask; | ||
| } |
| { | ||
| logger?.LogWarning( | ||
| "SignalR connection aborted due to origin mismatch. Origin={Origin}", | ||
| origin); |
Check failure
Code scanning / CodeQL
Log entries created from user input High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 days ago
In general, to fix log-forging issues, any user-controlled value should be normalized or encoded before being written to logs. For plain-text logs, this typically means removing or replacing newline characters (\r, \n) and possibly other non-printable control characters so an attacker cannot break the log format or inject extra entries. For logs destined to HTML, HTML-encoding is recommended.
In this specific code, the problematic value is origin read from Request.Headers["Origin"]. The best minimal fix is to sanitize this value once, immediately after reading it, and then use the sanitized value for all logging calls. That keeps observable behavior the same for normal Origin values while stripping potentially dangerous characters (such as newlines) that could be used for log forging. A simple approach, consistent with the recommendation, is to replace any \r and \n with empty strings (or another benign character). We should not alter other logic (such as the origin comparison) unless necessary; to keep functionality unchanged, we can continue to use the original origin for the origin-check logic and use a separate sanitized variable for logging.
Concretely in api/Hubs/NotificationsHub.cs:
- After obtaining
originat line 23, introduce a new variable, e.g.,sanitizedOrigin, which isoriginwith\rand\nremoved. - Update all logging calls that currently pass
originas a parameter (lines 25–28 and 50–52) to passsanitizedOrigininstead. - No new external dependencies are needed; this can be done using
string.Replace, which is part of the base class library.
This keeps the origin-matching logic identical (still using the original header value) while ensuring logged values cannot contain raw newlines.
| @@ -21,10 +21,13 @@ | ||
| var allowedOrigin = config?.GetValue<string>("CORS_DOMAIN"); | ||
| var disableOriginCheck = config?.GetValue<bool>("DISABLE_SIGNALR_ORIGIN_CHECK") ?? false; | ||
| var origin = httpContext?.Request.Headers["Origin"].ToString(); | ||
| var sanitizedOrigin = origin? | ||
| .Replace("\r", string.Empty) | ||
| .Replace("\n", string.Empty); | ||
|
|
||
| logger?.LogInformation( | ||
| "SignalR connect attempt. Origin={Origin}, CORS_DOMAIN={CorsDomain}", | ||
| origin, | ||
| sanitizedOrigin, | ||
| allowedOrigin); | ||
|
|
||
| if (disableOriginCheck) | ||
| @@ -49,7 +49,7 @@ | ||
| { | ||
| logger?.LogWarning( | ||
| "SignalR connection aborted due to origin mismatch. Origin={Origin}", | ||
| origin); | ||
| sanitizedOrigin); | ||
| Context.Abort(); | ||
| return Task.CompletedTask; | ||
| } |


NOT a pull request, just sharing a POC.
This is not production ready, as it doesn't have a backplane or proper controls on connections or message size/rates.
Requires these env vars to run:
export CORS_DOMAIN='https://localhost:8080;http://localhost:8080'
export VITE_WS_PROXY_INSECURE=true
export VITE_WS_PROXY_ORIGIN=https://localhost:8080