Lire en anglais

Partager via


Liste d’adresses IP du client approuvées pour ASP.NET Core

Par Damien Bowden et Tom Dykstra

Cet article présente trois façons d’implémenter une liste sécurisée d’adresses IP (également appelée liste verte) dans une application ASP.NET Core. Un exemple d’application associé illustre les trois approches. Vous pouvez utiliser :

  • Intergiciel pour case activée l’adresse IP distante de chaque requête.
  • L’action MVC filtre pour case activée l’adresse IP distante des requêtes pour des contrôleurs ou des méthodes d’action spécifiques.
  • RazorPages filtre pour case activée l’adresse IP distante des demandes de Razor pages.

Dans chaque cas, une chaîne contenant des adresses IP clientes approuvées est stockée dans un paramètre d’application. Intergiciel ou filtre :

  • Analyse la chaîne dans un tableau.
  • Vérifie si l’adresse IP distante existe dans le tableau.

L’accès est autorisé si le tableau contient l’adresse IP. Sinon, un code http 403 Forbidden status est renvoyé.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Liste sécurisée d’adresses IP

Dans l’exemple d’application, la liste des adresses IP approuvées est la suivante :

JSON
{
  "AdminSafeList": "127.0.0.1;192.168.1.5;::1",
  "Logging": {

Dans l’exemple précédent, les adresses IPv4 de 127.0.0.1 et 192.168.1.5 et l’adresse de bouclage IPv6 de ::1 (format compressé pour 0:0:0:0:0:0:0:1) sont autorisées.

Middleware

La Startup.Configure méthode ajoute le type d’intergiciel personnalisé AdminSafeListMiddleware au pipeline de demandes de l’application. La liste sécurisée est récupérée avec le fournisseur de configuration .NET Core et est passée en tant que paramètre de constructeur.

C#
app.UseMiddleware<AdminSafeListMiddleware>(Configuration["AdminSafeList"]);

L’intergiciel analyse la chaîne dans un tableau et recherche l’adresse IP distante dans le tableau. Si l’adresse IP distante est introuvable, l’intergiciel renvoie HTTP 403 Interdit. Ce processus de validation est contourné pour les requêtes HTTP GET.

C#
public class AdminSafeListMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<AdminSafeListMiddleware> _logger;
    private readonly byte[][] _safelist;

    public AdminSafeListMiddleware(
        RequestDelegate next,
        ILogger<AdminSafeListMiddleware> logger,
        string safelist)
    {
        var ips = safelist.Split(';');
        _safelist = new byte[ips.Length][];
        for (var i = 0; i < ips.Length; i++)
        {
            _safelist[i] = IPAddress.Parse(ips[i]).GetAddressBytes();
        }

        _next = next;
        _logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Method != HttpMethod.Get.Method)
        {
            var remoteIp = context.Connection.RemoteIpAddress;
            _logger.LogDebug("Request from Remote IP address: {RemoteIp}", remoteIp);

            var bytes = remoteIp.GetAddressBytes();
            var badIp = true;
            foreach (var address in _safelist)
            {
                if (address.SequenceEqual(bytes))
                {
                    badIp = false;
                    break;
                }
            }

            if (badIp)
            {
                _logger.LogWarning(
                    "Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
                context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
                return;
            }
        }

        await _next.Invoke(context);
    }
}

Filtre d'action

Si vous souhaitez contrôler l’accès piloté par la liste sécurisée pour des contrôleurs MVC ou des méthodes d’action spécifiques, utilisez un filtre d’action. Par exemple :

C#
public class ClientIpCheckActionFilter : ActionFilterAttribute
{
    private readonly ILogger _logger;
    private readonly string _safelist;

    public ClientIpCheckActionFilter(string safelist, ILogger logger)
    {
        _safelist = safelist;
        _logger = logger;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
        _logger.LogDebug("Remote IpAddress: {RemoteIp}", remoteIp);
        var ip = _safelist.Split(';');
        var badIp = true;
        
        if (remoteIp.IsIPv4MappedToIPv6)
        {
            remoteIp = remoteIp.MapToIPv4();
        }
        
        foreach (var address in ip)
        {
            var testIp = IPAddress.Parse(address);
            
            if (testIp.Equals(remoteIp))
            {
                badIp = false;
                break;
            }
        }

        if (badIp)
        {
            _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", remoteIp);
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            return;
        }

        base.OnActionExecuting(context);
    }
}

Dans Startup.ConfigureServices, ajoutez le filtre d’action à la collection filtres MVC. Dans l’exemple suivant, un filtre d’action ClientIpCheckActionFilter est ajouté. Une liste sécurisée et un enregistreur d’événements de console instance sont passés en tant que paramètres de constructeur.

C#
services.AddScoped<ClientIpCheckActionFilter>(container =>
{
    var loggerFactory = container.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger<ClientIpCheckActionFilter>();

    return new ClientIpCheckActionFilter(
        Configuration["AdminSafeList"], logger);
});
C#
services.AddScoped<ClientIpCheckActionFilter>(_ =>
{
    var logger = _loggerFactory.CreateLogger<ClientIpCheckActionFilter>();
    
    return new ClientIpCheckActionFilter(
        Configuration["AdminSafeList"], logger);
});

Le filtre d’action peut ensuite être appliqué à un contrôleur ou à une méthode d’action avec l’attribut [ServiceFilter] :

C#
[ServiceFilter(typeof(ClientIpCheckActionFilter))]
[HttpGet]
public IEnumerable<string> Get()

Dans l’exemple d’application, le filtre d’action est appliqué à la méthode d’action du Get contrôleur. Quand vous testez l’application en envoyant :

  • Requête HTTP GET, l’attribut [ServiceFilter] valide l’adresse IP du client. Si l’accès à la Get méthode d’action est autorisé, une variante de la sortie de console suivante est produite par le filtre d’action et la méthode d’action :

    dbug: ClientIpSafelistComponents.Filters.ClientIpCheckActionFilter[0]
          Remote IpAddress: ::1
    dbug: ClientIpAspNetCore.Controllers.ValuesController[0]
          successful HTTP GET    
    
  • Verbe de requête HTTP autre que GET, l’intergiciel AdminSafeListMiddleware valide l’adresse IP du client.

Razor Filtre pages

Si vous souhaitez contrôler l’accès par liste sécurisée pour une Razor application Pages, utilisez un Razor filtre Pages. Par exemple :

C#
public class ClientIpCheckPageFilter : IPageFilter
{
    private readonly ILogger _logger;
    private readonly IPAddress[] _safelist;

    public ClientIpCheckPageFilter(
        string safelist,
        ILogger logger)
    {
        var ips = safelist.Split(';');
        _safelist = new IPAddress[ips.Length];
        for (var i = 0; i < ips.Length; i++)
        {
            _safelist[i] = IPAddress.Parse(ips[i]);
        }

        _logger = logger;
    }

    public void OnPageHandlerExecuting(PageHandlerExecutingContext context)
    {
        var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
        if (remoteIp.IsIPv4MappedToIPv6)
        {
            remoteIp = remoteIp.MapToIPv4();
        }
        _logger.LogDebug(
            "Remote IpAddress: {RemoteIp}", remoteIp);

        var badIp = true;
        foreach (var testIp in _safelist)
        {
            if (testIp.Equals(remoteIp))
            {
                badIp = false;
                break;
            }
        }

        if (badIp)
        {
            _logger.LogWarning(
                "Forbidden Request from Remote IP address: {RemoteIp}", remoteIp);
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            return;
        }
    }

    public void OnPageHandlerExecuted(PageHandlerExecutedContext context)
    {
    }

    public void OnPageHandlerSelected(PageHandlerSelectedContext context)
    {
    }
}

Dans Startup.ConfigureServices, activez le Razor filtre Pages en l’ajoutant à la collection de filtres MVC. Dans l’exemple suivant, un filtre de Pages ClientIpCheckPageFilterRazor est ajouté. Une liste sécurisée et un enregistreur d’événements de console instance sont passés en tant que paramètres de constructeur.

C#
services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        var logger = LoggerFactory.Create(builder => builder.AddConsole())
                        .CreateLogger<ClientIpCheckPageFilter>();
        var filter = new ClientIpCheckPageFilter(
            Configuration["AdminSafeList"], logger);
        
        options.Filters.Add(filter);
    });
C#
services.AddMvc(options =>
{
    var logger = _loggerFactory.CreateLogger<ClientIpCheckPageFilter>();
    var clientIpCheckPageFilter = new ClientIpCheckPageFilter(
        Configuration["AdminSafeList"], logger);
    
    options.Filters.Add(clientIpCheckPageFilter);
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

Lorsque la page IndexRazor de l’exemple d’application est demandée, le Razor filtre Pages valide l’adresse IP du client. Le filtre produit une variante de la sortie de console suivante :

dbug: ClientIpSafelistComponents.Filters.ClientIpCheckPageFilter[0]
      Remote IpAddress: ::1

Ressources supplémentaires