ETC

.NET Core ASP.NET API에서 외부 IP를 차단하고, 그 차단 목록이 DB에 저장되어 있는 경우, 다음과 같은 방식으로 구현할 수 있습니다.

NicSub 2025. 7. 30. 14:17
728x90
반응형

✅ 구현 전략 요약

 

  1. 미들웨어에서 클라이언트 IP 확인
  2. DB에서 차단된 IP 목록 조회
  3. 요청이 차단된 IP에서 온 경우 403 Forbidden 반환

✅ 1. 미들웨어 방식 (가장 추천)

 

ASP.NET Core의 커스텀 미들웨어(Middleware) 를 사용하면 모든 요청 전에 IP를 검사할 수 있습니다.

<IP 차단 미들웨어>
public class IpBlockingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<IpBlockingMiddleware> _logger;

    public IpBlockingMiddleware(RequestDelegate next, ILogger<IpBlockingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context, IBlockedIpService blockedIpService)
    {
        var remoteIp = context.Connection.RemoteIpAddress?.ToString();

        if (string.IsNullOrEmpty(remoteIp))
        {
            await _next(context);
            return;
        }

        if (await blockedIpService.IsBlockedAsync(remoteIp))
        {
            _logger.LogWarning($"Blocked request from IP: {remoteIp}");
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            await context.Response.WriteAsync("Forbidden: Your IP is blocked.");
            return;
        }

        await _next(context);
    }
}

 

<서비스 인터페이스>
public
 interface IBlockedIpService
{
    Task<bool> IsBlockedAsync(string ipAddress);
}

<구현예시: EF Core>
public class BlockedIpService : IBlockedIpService
{
    private readonly AppDbContext _dbContext;

    public BlockedIpService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<bool> IsBlockedAsync(string ipAddress)
    {
        return await _dbContext.BlockedIps
            .AnyAsync(b => b.IpAddress == ipAddress);
    }
}

<미들웨어 등록>
app.UseMiddleware<IpBlockingMiddleware>();

<서비스 등록>
builder.Services.AddScoped<IBlockedIpService, BlockedIpService>();

 

 

✅ 2. 성능 최적화 (옵션)

DB 조회가 느릴 수 있으니, 차단 IP를 캐싱하거나 메모리에 로드해 두는 것도 좋습니다.

public class BlockedIpService : IBlockedIpService
{
    private readonly IMemoryCache _cache;
    private readonly AppDbContext _dbContext;
    private static readonly string CacheKey = "BlockedIpList";

    public BlockedIpService(AppDbContext dbContext, IMemoryCache cache)
    {
        _dbContext = dbContext;
        _cache = cache;
    }

    public async Task<bool> IsBlockedAsync(string ipAddress)
    {
        var blockedIps = await _cache.GetOrCreateAsync(CacheKey, async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);
            return await _dbContext.BlockedIps
                .Select(b => b.IpAddress)
                .ToListAsync();
        });

        return blockedIps.Contains(ipAddress);
    }
}


✅ 3. 클라이언트 IP 가져오기 주의점

실제 IP는 프록시를 통해 올 수 있음


var ip = context.Connection.RemoteIpAddress?.ToString();
하지만 프록시 서버나 로드밸런서가 있는 경우에는 X-Forwarded-For 헤더를 사용해야 정확함.


var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault()
         ?? context.Connection.RemoteIpAddress?.ToString();

⚠️ 주의: X-Forwarded-For는 조작될 수 있으므로 보안 고려 필요

 

✅ 요약 정리

목적구현 방식

모든 요청에서 IP 차단 ✅ 커스텀 미들웨어
차단 IP는 DB에서 조회 IBlockedIpService 활용
성능 최적화 MemoryCache 사용
실제 클라이언트 IP 확인 X-Forwarded-For 고려 필요

 

반응형