dotnet / docfx

Static site generator for .NET API documentation.
https://dotnet.github.io/docfx/
MIT License
3.94k stars 839 forks source link

[Bug] DocFX generated HTML fails Content Security Policy #10018

Open iSatishYadav opened 2 weeks ago

iSatishYadav commented 2 weeks ago

Describe the bug DocFX generated HTML produces following Content Security Policy errors when under restricted CSP e.g., self.

  1. index.html:

    <script>
        const theme = localStorage.getItem('theme') || 'auto'
        document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
    </script>
  2. index.html:

    <button class="btn btn-lg border-0 d-md-none" style="margin-top: -.65em; margin-left: -.8em" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
  3. nav.ts:115

    anchors.add('article h2:not(.no-anchor), article h3:not(.no-anchor), article h4:not(.no-anchor)')

    Almost of the CSS and JS are in their own files, except for those.

To Reproduce Steps to reproduce the behavior:

  1. Generate DocFX HTML
  2. Use following CSP headers:

Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self' data:; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com

Expected behavior The generated HTML files should not produce any CSP errors. This will ensure the HTML works under secure and restricted environments where tight Content Security Policies have been applied.

Context:

{
  "metadata": [
    {
      "src": [
        {
          "src": ".",
          "files": [
            "**/*.csproj"
          ]
        }
      ],
      "dest": "api"
    }
  ],
  "build": {
    "content": [
      {
        "files": [
         "**/*.{md,yml}"    
        ],
        "exclude": [
          "_site/**"
        ]
      }
    ],
    "resource": [
      {
        "files": [
          "images/**"
        ]
      }
    ],
    "output": "_site",
    "template": [
      "default",
      "modern"
    ],
    "globalMetadata": {
      "_appName": "Documentation",
      "_appTitle": "Documentation",
      "_enableSearch": true,
      "pdf": true
    }
  }
}
// Paste the full exception with stacktrace here, remove sensitive info
// Paste warnings or errors related to this bug here, remove sensitive info
endpoints.html:35  Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-EqCpmPzzL1OBCKRrI480jhMLWMTYbVQgeZZftbEm4yE='), or a nonce ('nonce-...') is required to enable inline execution.

endpoints.html:80  Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https://fonts.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-hrMAdouS/Nq0Km7HyvR/ocksu2luFnpaxSswePO7FOY='), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present.

nav.ts:115  Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https://fonts.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.
// Paste `dotnet --info` output here
.NET SDK:
 Version:           8.0.205
 Commit:            3e1383b780
 Workload version:  8.0.200-manifests.00402117

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22631
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.205\

.NET workloads installed:
 [android]
   Installation Source: VS 17.9.34902.65
   Manifest Version:    34.0.52/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.52\WorkloadManifest.json
   Install Type:              Msi

 [maccatalyst]
   Installation Source: VS 17.9.34902.65
   Manifest Version:    17.2.8004/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.2.8004\WorkloadManifest.json
   Install Type:              Msi

 [ios]
   Installation Source: VS 17.9.34902.65
   Manifest Version:    17.2.8004/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.2.8004\WorkloadManifest.json
   Install Type:              Msi

 [maui-windows]
   Installation Source: VS 17.9.34902.65
   Manifest Version:    8.0.7/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.7\WorkloadManifest.json
   Install Type:              Msi

Host:
  Version:      8.0.6
  Architecture: x64
  Commit:       3b8b000a0e

.NET SDKs installed:
  4.1.426 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  6.0.321 [C:\Program Files\dotnet\sdk]
  6.0.423 [C:\Program Files\dotnet\sdk]
  8.0.106 [C:\Program Files\dotnet\sdk]
  8.0.205 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Please let me know if any information I can provide to help. This is my first issue here, please excuse any rookie mistakes.

filzrev commented 2 weeks ago

It seems CSP errors can be suppressed by explicitly setting hash-source value as noted on reported error message. (Except for style="" attributes. that is fixed by #10020)

Example CSP error message and how to fix error

index.html:35 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-EqCpmPzzL1OBCKRrI480jhMLWMTYbVQgeZZftbEm4yE='), or a nonce ('nonce-...') is required to enable inline execution.

It need to add 'sha256-EqCpmPzzL1OBCKRrI480jhMLWMTYbVQgeZZftbEm4yE=' hash to script-src section.

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' https://fonts.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.

It need to add 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' hash to style-src section.


I've confirmed reported CSP errors can be fixed by adding above settings (and PR #10020) But when using mermaid.js or Math Expression Additional CSP errors occurs and needs additional settings.

iSatishYadav commented 1 week ago

Hi, is it possible to move the inline JavaScript code present in HTML to a separate JavaScript file? Thai will ensure the CSP errors related to inline scripts can be avoided.

Adding hash afterwards in HTML is not practical in my opinion as:

Please let me know if I'm missing something.

filzrev commented 1 week ago

is it possible to move the inline JavaScript code present in HTML to a separate JavaScript file?

Some CSP errors can be suppressed by separating to files. But there are errors that caused by dependent libraries (e.g. anchor-js, meramaid.js)

So these errors needs to be suppressed by specifying hash to response header,

iSatishYadav commented 5 days ago

Okay. Then docfx itself should add these hashes in the HTML while generating it at the time of docfx build or docfx serve.

filzrev commented 5 days ago

Okay. Then docfx itself should add these hashes in the HTML while generating it at the time of docfx build or docfx serve.

If Content-Security-Policy Response Header is set by web server. It can't override setting by docfx generated HTML side.

As far as I've tested. When specifying CSP on both Response Header and <meta> tag. It seems Most Restrictive rules are enabled. as described at following link. https://stackoverflow.com/questions/51148998/what-is-happening-when-i-have-two-csp-content-security-policies-policies-hea

iSatishYadav commented 3 days ago

This one can also be resolved by docfx, right?

<script>
        const theme = localStorage.getItem('theme') || 'auto'
        document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>

For external dependencies, let's take it up with respective libraries.

filzrev commented 3 days ago

This one can also be resolved by docfx, right?

Yes. it can be resolved by modifying modern template. As far as I knows following inline scripts need to be modified.

  1. theme switch script that described abobe.
  2. Google Analytics related script (If it's enabled)
  3. default template's inline script that reported at #4676