Skip to content

Commit

Permalink
feat(proxy): add ForwardedOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Aug 7, 2023
1 parent 31413cf commit 7e8eb44
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 7 deletions.
21 changes: 18 additions & 3 deletions docs/pages/config/appsettings.zh.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,17 @@ import { Callout } from "nextra-theme-docs";
"Secretkey": "",
"RecaptchaThreshold": "0.5"
},
"ForwardedHeadersOptions": {
"ForwardedOptions": {
"ForwardedHeaders": 5, // a flag enum, see following link
"ForwardLimit": 1,
"ForwardedForHeaderName": "X-Forwarded-For"
"ForwardedForHeaderName": "X-Forwarded-For",
// use the following options to allow proxy
"TrustedNetworks": [
"10.0.0.0/8"
],
"TrustedProxies": [
"10.0.0.1"
]
}
}
```
Expand Down Expand Up @@ -184,12 +191,20 @@ GZCTF 仅支持 PostgreSQL 作为数据库,不支持 MySQL 等其他数据库
- **Secretkey:** Google Recaptcha 服务器密钥
- **RecaptchaThreshold:** Google Recaptcha 阈值,用于判断验证码是否有效

### ForwardedHeadersOptions
### ForwardedOptions

此处配置反向代理的相关信息,用于获取真实 IP 地址,可选项。

- **ForwardedHeaders:** 反向代理转发的标头枚举,默认请使用 `5`,详情请见 [ForwardedHeaders 枚举](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.httpoverrides.forwardedheaders?view=aspnetcore-7.0)
- **ForwardLimit:** 反向代理层数限制
- **ForwardedForHeaderName:** 反向代理 IP 地址头名称
- **TrustedNetworks:** 反向代理信任的网络列表,使用 CIDR 表示
- **TrustedProxies:** 反向代理信任的代理列表,使用 IP 地址或域名表示

<Callout type="info">

若想要忽略反向代理的信任列表,允许任意 IP 地址访问,请参考[转发 Linux 和非 IIS 反向代理的方案](https://learn.microsoft.com/zh-cn/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-7.0#forward-the-scheme-for-linux-and-non-iis-reverse-proxies),设置环境变量 `ASPNETCORE_FORWARDEDHEADERS_ENABLED``true`

</Callout>

其他字段请参考官方文档描述:[配置 ASP.NET Core 以使用代理服务器和负载均衡器](https://learn.microsoft.com/zh-cn/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-7.0)[ForwardedHeadersOptions 类](https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.builder.forwardedheadersoptions?view=aspnetcore-7.0)
13 changes: 12 additions & 1 deletion src/GZCTF/Extensions/OtherExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GZCTF.Utils;
using System.Net;
using GZCTF.Utils;

namespace GZCTF.Extensions;

Expand Down Expand Up @@ -33,3 +34,13 @@ public static ArrayResponse<T> ToResponse<T>(this IEnumerable<T> array, int? tot
_ => new(array.ToArray(), tot)
};
}

public static class IPAddressExtensions
{
public static IPAddress[] ResolveIP(this string? host)
{
return (!string.IsNullOrWhiteSpace(host))
? Dns.GetHostAddresses(host)
: Array.Empty<IPAddress>();
}
}
41 changes: 40 additions & 1 deletion src/GZCTF/Models/Internal/Configs.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System.Text.Json.Serialization;
using System.Net;
using System.Reflection;
using System.Text.Json.Serialization;
using GZCTF.Extensions;
using Microsoft.AspNetCore.HttpOverrides;

namespace GZCTF.Models.Internal;

Expand Down Expand Up @@ -128,3 +132,38 @@ public class RecaptchaConfig
public string VerifyAPIAddress { get; set; } = "https://www.recaptcha.net/recaptcha/api/siteverify";
public float RecaptchaThreshold { get; set; } = 0.5f;
}

public class ForwardedOptions : ForwardedHeadersOptions
{
public List<string>? TrustedNetworks { get; set; }
public List<string>? TrustedProxies { get; set; }

public void ToForwardedHeadersOptions(ForwardedHeadersOptions options)
{
// assign the same value to the base class via reflection
var type = typeof(ForwardedHeadersOptions);
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
// skip the properties that are not being set directly
if (property.Name == nameof(KnownNetworks) ||
property.Name == nameof(KnownProxies))
continue;

property.SetValue(options, property.GetValue(this));
}

TrustedNetworks?.ForEach((network) =>
{
// split the network into address and prefix length
var parts = network.Split('/');
if (parts.Length == 2 && int.TryParse(parts[1], out var prefixLength))
{
var address = IPAddress.Parse(parts[0]);
options.KnownNetworks.Add(new IPNetwork(address, prefixLength));
}
});

TrustedProxies?.ForEach((proxy) => proxy.ResolveIP().ToList().ForEach((ip) => options.KnownProxies.Add(ip)));
}
}
15 changes: 14 additions & 1 deletion src/GZCTF/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,20 @@
builder.Services.Configure<GlobalConfig>(builder.Configuration.GetSection(nameof(GlobalConfig)));
builder.Services.Configure<GamePolicy>(builder.Configuration.GetSection(nameof(GamePolicy)));
builder.Services.Configure<ContainerProvider>(builder.Configuration.GetSection(nameof(ContainerProvider)));
builder.Services.Configure<ForwardedHeadersOptions>(builder.Configuration.GetSection(nameof(ForwardedHeadersOptions)));

var forwardedOptions = builder.Configuration.GetSection(nameof(ForwardedOptions)).Get<ForwardedOptions>();
if (forwardedOptions is null)
{
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
}
else
{
builder.Services.Configure<ForwardedHeadersOptions>(forwardedOptions.ToForwardedHeadersOptions);
}

if (builder.Configuration.GetSection(nameof(ContainerProvider))
.GetValue<ContainerProviderType>(nameof(ContainerProvider.Type))
Expand Down
6 changes: 5 additions & 1 deletion src/GZCTF/Utils/PrelaunchHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public async static Task RunPrelaunchWork(this WebApplication app)
{
using var serviceScope = app.Services.GetRequiredService<IServiceScopeFactory>().CreateScope();

var logger = serviceScope.ServiceProvider.GetRequiredService<ILogger<Program>>();
var context = serviceScope.ServiceProvider.GetRequiredService<AppDbContext>();
var cache = serviceScope.ServiceProvider.GetRequiredService<IDistributedCache>();

Expand Down Expand Up @@ -48,7 +49,10 @@ await context.Posts.AddAsync(new()
EmailConfirmed = true,
RegisterTimeUTC = DateTimeOffset.UtcNow
};
await usermanager.CreateAsync(admin, password);

var result = await usermanager.CreateAsync(admin, password);
if (!result.Succeeded)
logger.SystemLog($"管理员账户创建失败,错误信息:{result.Errors.FirstOrDefault()?.Description}", TaskStatus.Failed, LogLevel.Debug);
}
}

Expand Down

0 comments on commit 7e8eb44

Please sign in to comment.