cd8c78d165
CI - Build & Test / Backend (.NET) (push) Successful in 45s
CI - Build & Test / Backend integration (PostgreSQL/Toxiproxy) (push) Failing after 1m0s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m49s
CI - Build & Test / Security Check (push) Successful in 7s
CI - Build & Test / Deploy Nexus (push) Has been skipped
38 lines
1.5 KiB
C#
38 lines
1.5 KiB
C#
namespace Nexus.Api.Security;
|
|
|
|
/// <summary>
|
|
/// Rejects browser requests that explicitly identify themselves as cross-site.
|
|
/// Requests without browser provenance headers remain valid for trusted API
|
|
/// clients; they still need the normal cookie, authentication and rate limits.
|
|
/// </summary>
|
|
public static class BrowserRequestOriginGuard
|
|
{
|
|
public static bool IsAllowed(HttpRequest request)
|
|
{
|
|
var fetchSite = request.Headers["Sec-Fetch-Site"].ToString().Trim();
|
|
if (string.Equals(fetchSite, "cross-site", StringComparison.OrdinalIgnoreCase))
|
|
return false;
|
|
|
|
var originValue = request.Headers.Origin.ToString().Trim();
|
|
if (originValue.Length == 0)
|
|
return true;
|
|
|
|
if (!Uri.TryCreate(originValue, UriKind.Absolute, out var origin))
|
|
return false;
|
|
|
|
var requestHost = request.Host.Host;
|
|
if (requestHost.Length == 0)
|
|
return false;
|
|
|
|
var originPort = origin.IsDefaultPort ? DefaultPort(origin.Scheme) : origin.Port;
|
|
var requestPort = request.Host.Port ?? DefaultPort(request.Scheme);
|
|
|
|
return string.Equals(origin.Scheme, request.Scheme, StringComparison.OrdinalIgnoreCase)
|
|
&& string.Equals(origin.Host, requestHost, StringComparison.OrdinalIgnoreCase)
|
|
&& originPort == requestPort;
|
|
}
|
|
|
|
private static int DefaultPort(string scheme)
|
|
=> string.Equals(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) ? 443 : 80;
|
|
}
|