Fichiers statiques dans ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Par Rick Anderson

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateBuilder définit le répertoire actif comme racine du contenu :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Délivrer des fichiers à la racine web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Program.cs, ce qui permet de délivrer les fichiers statiques :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

La surcharge de la méthode UseStaticFiles sans paramètres marque les fichiers à la racine web comme étant délivrables. Le balisage suivant référence wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le balisage précédent, le caractère tilde ~ pointe vers la racine web.

Délivrer des fichiers en dehors de la racine web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une demande à https://<hostname>/StaticFiles/images/red-rose.jpg délivre le fichier red-rose.jpg.

Le balisage suivant référence MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Pour délivrer des fichiers à partir de plusieurs emplacements, consultez Délivrer des fichiers à partir de plusieurs emplacements.

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent rend les fichiers statiques accessibles publiquement dans le cache local pendant une semaine (604800 secondes).

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points de terminaison tels que les contrôleurs, Razor Pages, etc., qui spécifient leurs propres exigences d’autorisation, n’utilisent pas la stratégie d’autorisation de secours. Par exemple, Razor Pages, les contrôleurs ou les méthodes d’action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l’attribut d’autorisation appliqué plutôt que la stratégie d’autorisation de secours.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.

  • Les délivrer via une méthode d’action à laquelle une autorisation est appliquée et à retourner un objet FileResult :

    [Authorize]
    public class BannerImageModel : PageModel
    {
        private readonly IWebHostEnvironment _env;
    
        public BannerImageModel(IWebHostEnvironment env) =>
            _env = env;
    
        public PhysicalFileResult OnGet()
        {
            var filePath = Path.Combine(
                    _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
    
            return PhysicalFile(filePath, "image/jpeg");
        }
    }
    

L’approche précédente nécessite une page ou un point de terminaison par fichier. Le code suivant retourne des fichiers ou charge des fichiers pour les utilisateurs authentifiés :

app.MapGet("/files/{fileName}",  IResult (string fileName) => 
    {
        var filePath = GetOrCreateFilePath(fileName);

        if (File.Exists(filePath))
        {
            return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
        }

        return TypedResults.NotFound("No file found with the supplied file name");
    })
    .WithName("GetFileByName")
    .RequireAuthorization("AuthenticatedUsers");

// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
    {
        // Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
        // Take a look at the `Utilities.IsFileValid` method that takes an IFormFile and validates its signature within the AllowedFileSignatures
        
        var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
        await SaveFileWithCustomFileName(file, fileSaveName);
        
        context.Response.Headers.Append("Location", linker.GetPathByName(context, "GetFileByName", new { fileName = fileSaveName}));
        return TypedResults.Ok("File Uploaded Successfully!");
    })
    .RequireAuthorization("AdminsOnly");

app.Run();

Pour obtenir l’exemple complet, consultez le dossier GitHub StaticFileAuth.

Exploration de répertoires

La navigation dans les répertoires permet de lister les répertoires dans les répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec AddDirectoryBrowser et UseDirectoryBrowser :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

AddDirectoryBrowserajoute les services requis par l’intergiciel de navigation de répertoire, notamment HtmlEncoder. Ces services peuvent être ajoutés par d’autres appels, tels que AddRazorPages, mais nous vous recommandons d’appeler AddDirectoryBrowser pour garantir que les services sont ajoutés dans toutes les applications.

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédents, les URL sont résolues comme suit :

URI Response
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/) à moins que l’option RedirectToAppendTrailingSlash de DefaultFilesOptions soit utilisée.

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

Considérez la page Razor suivante qui affiche le fichier /MyStaticFiles/image3.png :

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. L’exemple suivant appelle UseStaticFiles deux fois pour délivrer des fichiers à partir de wwwroot et de MyStaticFiles :

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Utilisation du code précédent :

Le code suivant met à jour WebRootFileProvider, qui permet au Tag Helper d’image de fournir une version :

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows ne respecte pas la casse, mais macOS et Linux la respectent.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Délivrez des fichiers en dehors de wwwroot en mettant à jour IWebHostEnvironment.WebRootPath

Quand IWebHostEnvironment.WebRootPath est défini sur un dossier autre que wwwroot :

  • Dans l’environnement de développement, les ressources statiques trouvées dans wwwroot et dans la mise à jour de IWebHostEnvironment.WebRootPath sont délivrées à partir de wwwroot.
  • Dans tout environnement autre que celui de développement, les ressources statiques en double sont délivrées à partir du dossier IWebHostEnvironment.WebRootPath mis à jour.

Considérez une application web créée avec le modèle web vide :

  • Contenant un fichier Index.html dans wwwroot et wwwroot-custom.

  • Avec le fichier Program.cs mis à jour suivant qui définit WebRootPath = "wwwroot-custom" :

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dans le code précédent, les demandes adressées à / :

  • Dans l’environnement de développement, retournent wwwroot/Index.html
  • Dans tout environnement autre que celui de développement, retournent wwwroot-custom/Index.html

Pour vous assurer que les ressources à partir de wwwroot-custom sont retournées, utilisez l’une des approches suivantes :

  • Supprimez les ressources nommées en double dans wwwroot.

  • Définissez "ASPNETCORE_ENVIRONMENT" dans Properties/launchSettings.json sur n’importe quelle valeur autre que "Development".

  • Désactivez complètement les ressources web statiques en définissant <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dans le fichier projet. AVERTISSEMENT, la désactivation des ressources web statiques désactive les bibliothèques de classes Razor.

  • Ajoutez le code JSON suivant au fichier projet :

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Le code suivant met à jour IWebHostEnvironment.WebRootPath vers une valeur de non-développement, garantissant que le contenu en double est retourné à partir de wwwroot-custom plutôt que wwwroot :

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Ressources supplémentaires

Par Rick Anderson et Kirk Larkin

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateBuilder définit le répertoire actif comme racine du contenu :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Délivrer des fichiers à la racine web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Program.cs, ce qui permet de délivrer les fichiers statiques :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

La surcharge de la méthode UseStaticFiles sans paramètres marque les fichiers à la racine web comme étant délivrables. Le balisage suivant référence wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le balisage précédent, le caractère tilde ~ pointe vers la racine web.

Délivrer des fichiers en dehors de la racine web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une demande à https://<hostname>/StaticFiles/images/red-rose.jpg délivre le fichier red-rose.jpg.

Le balisage suivant référence MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Pour délivrer des fichiers à partir de plusieurs emplacements, consultez Délivrer des fichiers à partir de plusieurs emplacements.

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent rend les fichiers statiques accessibles publiquement dans le cache local pendant une semaine (604800 secondes).

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points de terminaison tels que les contrôleurs, Razor Pages, etc., qui spécifient leurs propres exigences d’autorisation, n’utilisent pas la stratégie d’autorisation de secours. Par exemple, Razor Pages, les contrôleurs ou les méthodes d’action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l’attribut d’autorisation appliqué plutôt que la stratégie d’autorisation de secours.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.
  • Les délivrer via une méthode d’action à laquelle une autorisation est appliquée et à retourner un objet FileResult :
[Authorize]
public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) =>
        _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
                _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

Exploration de répertoires

La navigation dans les répertoires permet de lister les répertoires dans les répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec AddDirectoryBrowser et UseDirectoryBrowser :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

AddDirectoryBrowserajoute les services requis par l’intergiciel de navigation de répertoire, notamment HtmlEncoder. Ces services peuvent être ajoutés par d’autres appels, tels que AddRazorPages, mais nous vous recommandons d’appeler AddDirectoryBrowser pour garantir que les services sont ajoutés dans toutes les applications.

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédents, les URL sont résolues comme suit :

URI Response
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/) à moins que l’option RedirectToAppendTrailingSlash de DefaultFilesOptions soit utilisée.

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

Considérez la page Razor suivante qui affiche le fichier /MyStaticFiles/image3.png :

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. L’exemple suivant appelle UseStaticFiles deux fois pour délivrer des fichiers à partir de wwwroot et de MyStaticFiles :

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Utilisation du code précédent :

Le code suivant met à jour WebRootFileProvider, qui permet au Tag Helper d’image de fournir une version :

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows ne respecte pas la casse, mais macOS et Linux la respectent.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Délivrez des fichiers en dehors de wwwroot en mettant à jour IWebHostEnvironment.WebRootPath

Quand IWebHostEnvironment.WebRootPath est défini sur un dossier autre que wwwroot :

  • Dans l’environnement de développement, les ressources statiques trouvées dans wwwroot et dans la mise à jour de IWebHostEnvironment.WebRootPath sont délivrées à partir de wwwroot.
  • Dans tout environnement autre que celui de développement, les ressources statiques en double sont délivrées à partir du dossier IWebHostEnvironment.WebRootPath mis à jour.

Considérez une application web créée avec le modèle web vide :

  • Contenant un fichier Index.html dans wwwroot et wwwroot-custom.

  • Avec le fichier Program.cs mis à jour suivant qui définit WebRootPath = "wwwroot-custom" :

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dans le code précédent, les demandes adressées à / :

  • Dans l’environnement de développement, retournent wwwroot/Index.html
  • Dans tout environnement autre que celui de développement, retournent wwwroot-custom/Index.html

Pour vous assurer que les ressources à partir de wwwroot-custom sont retournées, utilisez l’une des approches suivantes :

  • Supprimez les ressources nommées en double dans wwwroot.

  • Définissez "ASPNETCORE_ENVIRONMENT" dans Properties/launchSettings.json sur n’importe quelle valeur autre que "Development".

  • Désactivez complètement les ressources web statiques en définissant <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dans le fichier projet. AVERTISSEMENT, la désactivation des ressources web statiques désactive les bibliothèques de classes Razor.

  • Ajoutez le code JSON suivant au fichier projet :

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Le code suivant met à jour IWebHostEnvironment.WebRootPath vers une valeur de non-développement, garantissant que le contenu en double est retourné à partir de wwwroot-custom plutôt que wwwroot :

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Ressources supplémentaires

Par Rick Anderson et Kirk Larkin

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

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

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateDefaultBuilder définit le répertoire actif comme racine du contenu :

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Le code précédent a été créé avec le modèle d’application web.

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Délivrer des fichiers à la racine web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Startup.Configure, ce qui permet de délivrer les fichiers statiques :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

La surcharge de la méthode UseStaticFiles sans paramètres marque les fichiers à la racine web comme étant délivrables. Le balisage suivant référence wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le code précédent, le caractère tilde ~/ pointe vers la racine web.

Délivrer des fichiers en dehors de la racine web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une demande à https://<hostname>/StaticFiles/images/red-rose.jpg délivre le fichier red-rose.jpg.

Le balisage suivant référence MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    const string cacheMaxAge = "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append(
                 "Cache-Control", $"public, max-age={cacheMaxAge}");
        }
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code précédent définit l’âge maximal à 604800 secondes (7 jours).

En-têtes de réponse montrant que l’en-tête Cache-Control a été ajouté

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // wwwroot css, JavaScript, and images don't require authentication.
    app.UseStaticFiles();   

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
                     Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();

        services.AddAuthorization(options =>
        {
            options.FallbackPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
        });
    }

    // Remaining code ommitted for brevity.

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points de terminaison tels que les contrôleurs, Razor Pages, etc., qui spécifient leurs propres exigences d’autorisation, n’utilisent pas la stratégie d’autorisation de secours. Par exemple, Razor Pages, les contrôleurs ou les méthodes d’action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l’attribut d’autorisation appliqué plutôt que la stratégie d’autorisation de secours.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.
  • Les délivrer via une méthode d’action à laquelle une autorisation est appliquée et à retourner un objet FileResult :
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

Exploration de répertoires

La navigation dans les répertoires permet de lister les répertoires dans les répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    var options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée. Le code suivant montre Startup.Configure avec UseFileServer :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

app.UseFileServer(enableDirectoryBrowsing: true);

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer(enableDirectoryBrowsing: true);

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(); // For the wwwroot folder.

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédent, les URL sont résolues comme suit :

URI Response
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/).

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages"
});

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.AspNetCore.StaticFiles;
    // using Microsoft.Extensions.FileProviders;
    // using System.IO;

    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. Pour plus d’informations, consultez ce problème GitHub.

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows ne respecte pas la casse, mais macOS et Linux la respectent.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Ressources supplémentaires