Tinyrack

コンテンツセキュリティポリシー

レスポンスごとの nonce で Base UI のスタイル・スクリプト要素を許可し、必要に応じて生成スタイルを静的 CSS に置き換えます。

CSP の動作を設定する

コンテンツセキュリティポリシーを適用するアプリケーションで、Tinyrack コンポーネントの Base UI 内部実装が <style> または <script> 要素を生成する場合は、TRCSPProvider を使用してください。2 つの機能は個別に設定します。

  1. サーバーレスポンスごとに nonce を生成し、HTTP ヘッダー、サーバーレンダリング、クライアントのハイドレーションへ同じ値を渡します。この nonce で Base UI のスタイル要素とスクリプト要素を許可できます。
  2. スタイル要素を一切レンダリングできない場合は、disableStyleElements も設定し、同等のスクロールバー規則を静的スタイルシートへ追加します。この設定ではスクリプト要素を無効にできないため、コンポーネントがスクリプトを生成する可能性があれば nonce を引き続き渡します。

プロバイダーが提供するのは Base UI のコンテキストです。HTTP ヘッダーを生成または送信せず、アプリケーションのほかの CSP 設定も変更しません。

インストール

Tailwind CSS 4 を設定した React 19 アプリケーションが前提です。UI パッケージをまだインストールしていない場合は、React のピア依存関係とともに追加してください。

pnpm add @tinyrack/ui react react-dom

プロバイダーのサブパスは CSS を追加しません。@tinyrack/ui/core.css と、レンダリングする各コンポーネントのスタイルを引き続き読み込んでください。

レスポンスごとに nonce を渡す

サーバーでレスポンスごとに nonce を 1 回生成してください。style-src-elem は Base UI の <style> 要素を許可し、script-src ディレクティブは同じ nonce が付いた Base UI の <script> 要素を許可します。この最小構成は、アプリケーション全体の CSP に合わせて調整してください。

import { randomBytes } from 'node:crypto';
import type { ReactNode } from 'react';
import { TRCSPProvider } from '@tinyrack/ui/providers/csp';

export function createRequestCsp() {
  const nonce = randomBytes(16).toString('base64');

  return {
    nonce,
    header: [
      "default-src 'self'",
      `style-src-elem 'self' 'nonce-${nonce}'`,
      `script-src 'self' 'nonce-${nonce}'`,
    ].join('; '),
  };
}

export function AppProviders({
  children,
  nonce,
}: {
  children: ReactNode;
  nonce: string;
}) {
  return <TRCSPProvider nonce={nonce}>{children}</TRCSPProvider>;
}

返された header をそのレスポンスに設定し、サーバーでレンダリングするプロバイダーに nonce を渡してから、ハイドレーションにも同じ値をシリアライズしてください。ブラウザーで別の nonce を生成しないでください。style-src-elem がある場合、スタイル要素は style-src とは別に制御されます。

生成されるスタイル要素を無効にする

ポリシーでインラインのスタイル要素を許可しない場合は、明示的に無効にしてください。disableStyleElements は Base UI のスクリプト要素を抑止しないため、レスポンスごとの nonce も引き続き渡します。

import type { ReactNode } from 'react';
import { TRCSPProvider } from '@tinyrack/ui/providers/csp';

export function AppProviders({
  children,
  nonce,
}: {
  children: ReactNode;
  nonce: string;
}) {
  return (
    <TRCSPProvider disableStyleElements nonce={nonce}>
      {children}
    </TRCSPProvider>
  );
}

次に、ポリシーで許可した静的スタイルシートへ、次の補助規則をそのまま追加します。

.base-ui-disable-scrollbar {
  scrollbar-width: none;
}

.base-ui-disable-scrollbar::-webkit-scrollbar {
  display: none;
}

現在 Tinyrack が使用する Base UI では、Scroll Area が Viewport にこのクラスを適用し、ネイティブのスクロールバーを隠してカスタムスクロールバーを表示します。アプリケーションで Scroll Area をレンダリングする場合は、静的規則を維持してください。Tinyrack Select はトリガー基準の配置を使用し、Base UI の項目整列配置モードを使用しません。

適用範囲を理解する

disableStyleElements が抑止するのは、Base UI の CSP コンテキストを通して生成されるスタイル要素だけです。Tinyrack、Base UI、アプリケーションコードが生成するインラインの style 属性は削除しません。この属性は style-src-attr などのディレクティブで別に制御されるため、アプリケーションのポリシーで扱いを決めてください。

プロバイダーは、アプリケーションが生成するその他の要素、フレームワークのスクリプト、サードパーティのタグ、スタイルシートに nonce を追加しません。これらのリソースには、フレームワークの CSP 連携を引き続き使用してください。基盤となる動作は Base UI CSP Provider のドキュメントで確認できます。

API

TRCSPProviderTRCSPProviderProps@tinyrack/ui/providers/csp からインポートしてください。

プロパティ型と既定値役割
childrenReactNode子孫の Base UI コンポーネントに CSP の値を提供します。
noncestring、既定値なしBase UI が生成する <style><script> 要素に、リクエストの nonce を追加します。
disableStyleElementsboolean、既定値は falseBase UI のスタイル要素をレンダリングしません。スクリプトには影響せず、アプリケーション側で同等の CSS を提供する必要があります。

ポリシーを検証する

ローカルの開発画面だけで判断せず、本番レスポンスを検査してください。

  1. レスポンスに意図した CSP ヘッダーがあり、その nonce がレンダリングされた Base UI 要素の値と一致することを確認します。
  2. 同じ nonce でハイドレーションし、ブラウザーコンソールまたは CSP のレポート送信先に違反がないことを確認します。
  3. スタイル要素を無効にした場合は、Scroll Area と項目をトリガーに揃える設定を有効にした Select を開き、Popup または List のネイティブスクロールバーが隠れ、カスタムスクロールが動作することを確認します。
  4. キーボードとタッチ操作でオーバーレイとスクロールロックを動かし、ポリシー適用下でも動作することを確認します。