Files
MoShiro/backend/tests/MoShiro.Backend.Tests/ClientAddressTests.cs
T
justme a19e6548d3 feat: trust forwarded client addresses only from configured proxies (rate limit, audit, SSE) [CI]
Docs: access.md covers the missing node-side Backend identity and the hash-first install flow.
2026-10-07 22:51:44 +08:00

52 lines
2.1 KiB
C#

using System.Net;
using Microsoft.AspNetCore.Http;
using MoShiro.Backend.Api;
using MoShiro.Backend.Application;
namespace MoShiro.Backend.Tests;
/// <summary>真实来源地址:只有从可信代理连进来的请求才采信转发头,而且取最右边第一个不可信的地址。</summary>
public sealed class ClientAddressTests
{
private static string Resolve(string? trusted, string remote, string? forwarded, string? header = null)
{
var resolver = new ClientAddressResolver(new BackendOptions { TrustedProxies = trusted, TrustedProxyHeader = header });
var http = new DefaultHttpContext();
http.Connection.RemoteIpAddress = IPAddress.Parse(remote);
if (forwarded is not null)
{
http.Request.Headers[header ?? "X-Forwarded-For"] = forwarded;
}
return resolver.Resolve(http);
}
[Fact]
public void WithoutTrustedProxies_TheSocketAddressIsUsed_AndTheHeaderIsIgnored() =>
Assert.Equal("203.0.113.9", Resolve(null, "203.0.113.9", "1.2.3.4"));
[Fact]
public void FromATrustedProxy_TheForwardedClientIsUsed() =>
Assert.Equal("198.51.100.7", Resolve("10.0.0.0/8", "10.1.2.3", "198.51.100.7"));
[Fact]
public void FromAnUntrustedPeer_TheHeaderIsIgnored() =>
Assert.Equal("203.0.113.9", Resolve("10.0.0.0/8", "203.0.113.9", "1.2.3.4"));
[Fact]
public void TheChainIsWalkedFromTheRight_SoAClientCannotForgeItsAddress() =>
Assert.Equal("198.51.100.7", Resolve("10.0.0.0/8,127.0.0.1", "10.1.2.3", "6.6.6.6, 198.51.100.7, 10.9.9.9"));
[Fact]
public void AGarbageHeader_FallsBackToTheSocketAddress() =>
Assert.Equal("10.1.2.3", Resolve("10.0.0.0/8", "10.1.2.3", "not-an-ip"));
[Fact]
public void ASingleAddressAndACustomHeaderWork() =>
Assert.Equal("198.51.100.7", Resolve("127.0.0.1", "127.0.0.1", "198.51.100.7", "CF-Connecting-IP"));
[Fact]
public void AMalformedTrustedProxyEntry_FailsAtStartup() =>
Assert.Throws<InvalidOperationException>(() => new ClientAddressResolver(new BackendOptions { TrustedProxies = "banana" }));
}