honojs / honox

HonoX - Hono based meta framework
https://hono.dev
MIT License
1.28k stars 38 forks source link

`nonce` attribute should be added only in production? #169

Closed yusukebe closed 3 months ago

yusukebe commented 4 months ago

What version of HonoX are you using?

0.1.16

What steps can reproduce the bug?

app/routes/_middleware:

import { createRoute } from 'honox/factory'
import { secureHeaders, NONCE } from 'hono/secure-headers'

export default createRoute(
  secureHeaders({
    contentSecurityPolicy: {
      scriptSrc: [NONCE],
      styleSrc: [NONCE]
    }
  })
)

app/routes/_renderer:

import { jsxRenderer } from 'hono/jsx-renderer'
import { Script } from 'honox/server'

export default jsxRenderer(({ children }, c) => {
  return (
    <html lang="en">
      <head>
        <Script src="/app/client.ts" async nonce={c.get('secureHeadersNonce')} />
      </head>
      <body>{children}</body>
    </html>
  )
})

Run the dev server locally:

npm run dev

What is the expected behavior?

The browser does not throw an error.

What do you see instead?

Throwing the error:

CleanShot 2024-05-05 at 09 51 08@2x

This is because the script element importing /@vite/client has no nonce.

CleanShot 2024-05-05 at 09 51 13@2x

Additional information

I think it does not need nonce in local development. <Script /> should have it only in production.

usualoma commented 4 months ago

I think this is not a Script component issue, but rather "how to apply secureHeaders middleware in production and development environments?" I think it's a similar issue to this, but I don't want to deal with it in such a complicated way.

https://github.com/vitejs/vite/issues/11862

It would be good to have default values (automatically distinguishing between development and production environments and appropriately selected values) that can be easily set by the user.

Prerequisite

This script element is 'sha256-skbsb8aC0J3t64Itv3lSwl9/M7LOJglCR99BjSMntzI='.

<script>import("/@vite/client")</script>

Managing with the current honox specifications

None of these are very pretty, but within the current specification they can be specified as follows.

Only in the development environment, add a setting

"'sha256-skbsb8aC0J3t64Itv3lSwl9/M7LOJglCR99BjSMntzI='" may be exported from honox.

import { createRoute } from "honox/factory";
import { secureHeaders, NONCE } from "hono/secure-headers";

export default createRoute(
  secureHeaders({
    contentSecurityPolicy: {
      scriptSrc: [
        ...(import.meta.env.PROD
          ? []
          : ["'self'", "'sha256-skbsb8aC0J3t64Itv3lSwl9/M7LOJglCR99BjSMntzI='"]),
        NONCE,
      ],
    },
  })
);

Only in the production environment, use NONCE

Set secureHeaders only in the production environment.

yusukebe commented 4 months ago

@usualoma Thank you for your valuable input.

I think this is not a Script component issue, but rather "how to apply secureHeaders middleware in production and development environments?"

AH, yes. You are right. I agree it!

None of these are very pretty, but within the current specification they can be specified as follows.

Cool. Or super simply, if we can allow it not to be enabled in local development env, we can turn on CSP completely, as you said at the bottom of your comment:

import { createRoute } from 'honox/factory'
import { secureHeaders, NONCE } from 'hono/secure-headers'

export default createRoute(
  secureHeaders({
    contentSecurityPolicy: import.meta.env.PROD
      ? {
          scriptSrc: [NONCE]
        }
      : undefined
  })
)
usualoma commented 4 months ago

Ah yes, that's good.

  secureHeaders({
    contentSecurityPolicy: import.meta.env.PROD
      ? {
          scriptSrc: [NONCE]
        }
      : undefined
  })
yusukebe commented 3 months ago

This can be resolved by the above way.