本文へ移動

TypeScriptとEdge Runtimeの境界を安全に実装する確認手順

TypeScriptの型が消える実行時境界、Edge Runtimeの制約、入力検証、認証・キャッシュ、ヘッダーを脅威ごとに確認する実装ガイドです。

公開: 更新: 著者: カテゴリ: AI×開発・自動化

読了目安:5分

TypeScriptとEdge Runtimeのセキュリティ確認

TypeScriptが通ったことは、ネットワークから届くJSON、Cookie、ヘッダー、環境変数の値が安全だという証明にはなりません。TypeScriptの型はJavaScript出力時に消えるため、実行時の境界では別の検証が必要です。TypeScript公式資料も、型注釈が消去されてJavaScriptが生成される仕組みを説明しています。

この記事は「これを設定すれば安全」と断定するものではありません。アプリ固有の資産、攻撃者、データ、認証方式を整理したうえで、実装とテストを対応させるための確認手順です。

1. 信頼境界を先に列挙する

コードを書く前に、外部から値が入る場所を一覧にします。

境界失敗時の影響
URL・本文query、JSON、FormData不正処理、負荷増大
認証情報Cookie、Authorizationなりすまし、権限昇格
キャッシュキーpath、header、user state他ユーザーへの応答混入
外部APIJSON、status、redirect誤処理、SSRF等の候補
秘密情報環境変数、鍵漏えい、署名偽造
ブラウザ出力HTML、script、headerXSS等の候補

「内部APIだから信頼する」ではなく、境界ごとに入力元、許可形式、最大サイズ、失敗時の応答を決めます。

2. unknownから実行時に絞り込む

外部入力を型アサーションだけで確定させません。次の例は依存ライブラリを使わず、必要なキーと値を実行時に検査します。

type SignupInput = {
  email: string;
  displayName: string;
};

export function parseSignupInput(value: unknown): SignupInput {
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
    throw new Error("invalid body");
  }

  const input = value as Record<string, unknown>;
  if (
    typeof input.email !== "string" ||
    input.email.trim().length < 1 ||
    input.email.length > 254 ||
    typeof input.displayName !== "string" ||
    input.displayName.trim().length < 1 ||
    input.displayName.length > 80
  ) {
    throw new Error("invalid fields");
  }

  return { email: input.email, displayName: input.displayName };
}

長さ制限や許可文字は業務要件に合わせます。OWASPの入力検証ガイドが説明するように、構文上正しいことと業務上妥当であることも分けて確認します。

3. Edge Runtimeの対応APIを実測する

Edge RuntimeはNode.jsランタイムと同一ではありません。VercelのEdge Runtime資料で利用可能なWeb APIと制限を確認し、実際のproduction相当環境で次をテストします。

  • 使用する暗号・ストリーム・エンコーディングAPI
  • 依存パッケージがNode.js専用APIを要求しないか
  • タイムアウト、レスポンスサイズ、地域設定
  • 失敗時に機密値がログや応答へ出ないか

地理的に分散していることだけでDDoS耐性や安全性が保証される、とは扱いません。

4. 認証とキャッシュを同じレビューで扱う

認証済み応答を共有キャッシュへ保存すると、入力検証が正しくても情報が混ざる可能性があります。各ルートで次を確認します。

  • 認証と認可を別々に実施する
  • ユーザー固有応答を共有キャッシュしない
  • キャッシュキーに必要な差分が含まれる
  • Cookie属性と有効期間を脅威モデルに合わせる
  • トークン失効、鍵ローテーション、時計ずれをテストする

「アクセストークンは必ず15分」「Cookieなら安全」のような一律値は置きません。HttpOnlyはJavaScriptからの読出しを制限しますが、すべてのXSSやCSRFを解決する設定ではありません。

5. 秘密情報とデプロイ設定を検査する

秘密鍵が未設定のまま処理を続けないよう、起動またはリクエストの早い段階で明示的に失敗させます。

export function requireSecret(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required secret: ${name}`);
  return value;
}

秘密値そのものをログへ出さず、PreviewとProductionで別の値と権限を使います。Vercelを利用する場合はConformanceのルール一覧も補助検査として使えますが、自動ルールだけでレビューを完了させません。

6. CSPとヘッダーをReport-Onlyから検証する

CSPはブラウザ側の多層防御の一つです。OWASPのCSPガイドは、まずContent-Security-Policy-Report-Onlyで違反を観測してから強制する方法を説明しています。

外部スクリプトやnonceを含むサイトでは、実際のHTMLとロード対象を一覧化し、代表ページで違反と動作を確認します。CSPを付けたという事実だけで「XSSを防止した」と評価しません。

レビュー完了条件

  • 各信頼境界に、許可形式・上限・失敗応答のテストがある
  • 認証済み・未認証・権限不足を別ケースで試した
  • ユーザー固有応答のキャッシュ挙動を確認した
  • 必須秘密情報が欠けると安全側に失敗する
  • ログとエラー本文へ秘密・個人情報が出ない
  • CSPと主要ヘッダーを実HTMLで確認した
  • Node.jsとEdge Runtimeの差をproduction相当で実行した

入力例と拒否理由を対応させる

上の関数は型と長さの境界を示す最小例で、メールアドレスの妥当性・所有確認・登録権限を完了する実装ではありません。空のメールや空白だけの表示名も拒否するよう補っていますが、業務上の許可文字や正規化は別途決めます。

テスト入力期待する結果
null、配列invalid body
emailが数値、空文字、254文字超invalid fields
displayNameが空白だけ、80文字超invalid fields
必要な文字列が範囲内2項目を返す。本人確認済みとは扱わない

これらは設計用の期待値です。本番相当のAPIでは、不正入力を400系へ変換し、例外のスタックや秘密情報を返さないことまで別にテストします。

結論

TypeScript、Edge Runtime、CSPは、それぞれ異なる層の道具です。型チェックを入力検証の代わりにせず、エッジ配信を攻撃耐性の証明にせず、ヘッダーを安全性の保証にしないことが出発点です。脅威と境界を列挙し、各対策に失敗テストを対応させて初めて、変更後も再確認できる実装になります。

確認した一次情報

主要な主張については、本文中にも対応する資料へのリンクを残しています。

  1. Content Security Policy Cheat SheetOWASP Foundation · security-guidance · 確認: 2026-07-26
  2. Input Validation Cheat SheetOWASP Foundation · security-guidance · 確認: 2026-07-26
  3. Conformance rulesVercel · official-documentation · 確認: 2026-07-26
  4. Edge RuntimeVercel · official-documentation · 確認: 2026-07-26
  5. TypeScript for the New ProgrammerMicrosoft · official-documentation · 確認: 2026-07-26

関連記事

著者

ImidefWorks

Next.jsブログ運営、AI開発、Macの設定を、確認手順・判断材料・一次情報に分けて記録する個人運営の書き手です。

著者プロフィールと編集方針を見る