Quantcast
Channel: damienbod – Software Engineering
Viewing all articles
Browse latest Browse all 357

Add a Swagger UI using a .NET 9 Json OpenAPI file

$
0
0

This post shows how to implement a Swagger UI using a .NET 9 produced OpenAPI file. The Swagger UI is deployed to a secure or development environment and is not deployed to a public production target. Sometimes, it is required to deploy the Swagger UI to a development deployment target and not the test or the production deployments. The security headers need to be weakened to allow the Swagger UI to work.

Code: https://github.com/damienbod/WebApiOpenApi

Setup

The post uses the OpenAPI Json created by a .NET 9 ASP.NET Core application. See this blog:

Implementing an ASP.NET Core API with .NET 9 and OpenAPI

Two further packages were added to this project, one for the generation of the Swagger UI and the second package to generate the required security headers for an API using JWT Bearer tokens.

  • Swashbuckle.AspNetCore.SwaggerUI
  • NetEscapades.AspNetCore.SecurityHeaders

The ASP.NET Core API application has already generated the OpenAPI definitions in a Json file. The Json can be used to create the UI. If the application is deployed to production, the Json file is not created and the security headers are deployed with the most restrictions. If the application is deployed for development, the Json is deployed and the security headers are weakened to allow this to work.

// Open up security restrictions to allow this to work
// Not recommended in production
//var deploySwaggerUI = app.Environment.IsDevelopment();
var deploySwaggerUI = app.Configuration.GetValue<bool>("DeploySwaggerUI");

app.UseSecurityHeaders(
    SecurityHeadersDefinitions.GetHeaderPolicyCollection(deploySwaggerUI));

// ... other middleware

app.MapOpenApi("/openapi/v1/openapi.json");

if (deploySwaggerUI)
{
    app.UseSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/openapi/v1/openapi.json", "v1");
    });
}

The DeploySwaggerUI configuration is used to specify if the deployed version supports both a UI and an API or just an API with the most restrictive security settings.

{
  // Open up security restrictions to allow this to work
  // Not recommended in production
  "DeploySwaggerUI": true,

Setup security headers

The security headers are setup so that if the deployment is for development, scripts and styles are allowed. The configuration allowing scripts is weak and not recommended for production.

namespace WebApiOpenApi;

public static class SecurityHeadersDefinitions
{
    public static HeaderPolicyCollection GetHeaderPolicyCollection(bool isDev)
    {
        var policy = new HeaderPolicyCollection()
            .AddFrameOptionsDeny()
            .AddContentTypeOptionsNoSniff()
            .AddReferrerPolicyStrictOriginWhenCrossOrigin()
            .AddCrossOriginOpenerPolicy(builder => builder.SameOrigin())
            .AddCrossOriginEmbedderPolicy(builder => builder.RequireCorp())
            .AddCrossOriginResourcePolicy(builder => builder.SameOrigin())
            .RemoveServerHeader()
            .AddPermissionsPolicy(builder =>
            {
                builder.AddAccelerometer().None();
                builder.AddAutoplay().None();
                builder.AddCamera().None();
                builder.AddEncryptedMedia().None();
                builder.AddFullscreen().All();
                builder.AddGeolocation().None();
                builder.AddGyroscope().None();
                builder.AddMagnetometer().None();
                builder.AddMicrophone().None();
                builder.AddMidi().None();
                builder.AddPayment().None();
                builder.AddPictureInPicture().None();
                builder.AddSyncXHR().None();
                builder.AddUsb().None();
            });

        AddCspHstsDefinitions(isDev, policy);

        policy.ApplyDocumentHeadersToAllResponses();

        return policy;
    }

    private static void AddCspHstsDefinitions(bool isDev, HeaderPolicyCollection policy)
    {
        if (!isDev)
        {
            policy.AddContentSecurityPolicy(builder =>
            {
                builder.AddObjectSrc().None();
                builder.AddBlockAllMixedContent();
                builder.AddImgSrc().None();
                builder.AddFormAction().None();
                builder.AddFontSrc().None();
                builder.AddStyleSrc().None();
                builder.AddScriptSrc().None();
                builder.AddBaseUri().Self();
                builder.AddFrameAncestors().None();
                builder.AddCustomDirective("require-trusted-types-for", "'script'");
            });
            // maxage = one year in seconds
            policy.AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365);
        }
        else
        {
            // allow swagger UI for dev
            policy.AddContentSecurityPolicy(builder =>
            {
                builder.AddObjectSrc().None();
                builder.AddBlockAllMixedContent();
                builder.AddImgSrc().Self().From("data:");
                builder.AddFormAction().Self();
                builder.AddFontSrc().Self();
                builder.AddStyleSrc().Self().UnsafeInline();
                builder.AddScriptSrc().Self().UnsafeInline(); //.WithNonce();
                builder.AddBaseUri().Self();
                builder.AddFrameAncestors().None();
            });
        }
    }
}

When the UI is deployed to in development mode, the Swagger UI is displayed and the user can enter a valid access token and use the APIs.

Notes

At present, the Swagger UI does not support script best practices and allowing this to work means deploying an unsecure web application with weak security. Any UI web application should use a strong CSP definition, for example like CSP nonces. An API has no UI and so should be locked down.

Links

https://github.com/martincostello/dotnet-minimal-api-integration-testing

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/aspnetcore-openapi

https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types

https://github.com/RicoSuter/NSwag

https://swagger.io/

https://swagger.io/specification/


Viewing all articles
Browse latest Browse all 357

Trending Articles