C#(ASP.NET Core)
ASP.NET Core アプリケーションは、ミドルウェアコンポーネントのパイプラインを通じて受信 HTTP リクエストを処理します。ProxyTracer ミドルウェアをパイプラインに追加することで、リクエストがコントローラーやエンドポイントに到達する前にクライアント IP アドレスを自動検証し、VPN やプロキシトラフィックを遮断できます。
ミドルウェアの実装
このミドルウェアは HttpContext からクライアント IP アドレスを読み取り、ProxyTracer API に高速な HTTP クエリを実行して、接続がプロキシまたは VPN としてフラグ付けされた場合に即座に 403 Forbidden JSON レスポンスを返します。
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace ProxyTracer.Security
{
public class ProxyTracerMiddleware
{
private readonly RequestDelegate _next;
private readonly HttpClient _httpClient;
private readonly ILogger<ProxyTracerMiddleware> _logger;
private readonly string _apiKey;
public ProxyTracerMiddleware(RequestDelegate next, IConfiguration config, ILogger<ProxyTracerMiddleware> logger)
{
_next = next;
_logger = logger;
_apiKey = config["PROXYTRACER_API_KEY"] ?? throw new ArgumentNullException("PROXYTRACER_API_KEY is missing");
// 厳格な500msのタイムアウトを持つ再利用可能なクライアント
_httpClient = new HttpClient { Timeout = TimeSpan.FromMilliseconds(500) };
}
public async Task InvokeAsync(HttpContext context)
{
// 1. IPを抽出 (Program.csでapp.UseForwardedHeaders()の設定が必要です)
var ip = context.Connection.RemoteIpAddress?.ToString();
// ローカル開発環境のIPをスキップ
if (!string.IsNullOrEmpty(ip) && ip != "127.0.0.1" && ip != "::1")
{
try
{
// 2. ProxyTracer APIに非同期でクエリを実行
using var request = new HttpRequestMessage(HttpMethod.Get, $"https://api.proxytracer.com/v1/check/{ip}");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _apiKey);
using var response = await _httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var jsonStream = await response.Content.ReadAsStreamAsync();
var ptResponse = await JsonSerializer.DeserializeAsync<ProxyTracerResult>(jsonStream);
// 3. プロキシ/VPNが検出された場合は接続を切断
if (ptResponse != null && ptResponse.Proxy)
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync("{\"error\": \"Access Denied: VPN or Proxy detected.\"}");
return; // リクエストパイプラインをショートサーキット(即時終了)
}
}
}
catch (Exception ex)
{
// フェイルオープン: エラーをログに記録し、リクエストの通過を許可
_logger.LogWarning($"ProxyTracer validation failed: {ex.Message}");
}
}
// 4. トラフィックは正常です。コントローラーへ処理を渡します
await _next(context);
}
// {"proxy": true|false} レスポンスに正確にマッピングする軽量な構造体
private class ProxyTracerResult
{
[JsonPropertyName("proxy")]
public bool Proxy { get; set; }
}
}
}設定:
設定時の注意: このミドルウェアは、リクエストパイプラインの早い段階(Program.cs 内の app.UseRouting() の直後、または認証・認可ミドルウェアの前)に登録してください。
var app = builder.Build();
// 1. NGINX/Cloudflareロードバランサーの背後にある場合、実際のIPが抽出されることを確認
app.UseForwardedHeaders();
// 2. 悪意あるトラフィックを早期に遮断
app.UseMiddleware<ProxyTracer.Security.ProxyTracerMiddleware>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();最終更新日: