How to Think About Security in Next.js を読む
に公開How to Think About Security in Next.js を読んだまとめ
データ処理モデル
HTTP API(既存の大規模プロジェクト/組織向け)
- Server ComponentsをSSRまたはクライアント内でデフォルトでunsafe/untrustedとして扱うことを推奨。
- ゼロトラストのコンセプトを適用する。
- 既存のセキュリティプラクティスを維持できるようにするため、RESTやGraphQLなどのカスタムAPIエンドポイントを呼び出すことを推奨。
データアクセスレイヤー(新規プロジェクト向け)
- データアクセスレイヤーを作成し、すべてのデータアクセスを統合することを推奨。
- データアクセスを一貫させ、認可のバグが発生する可能性を減少させることができる。
- 実行時のオーバーヘッドが低く、リクエストの異なる部分でインメモリキャッシュを共有できるなど、パフォーマンスの向上も期待できる。
コンポーネントレベルのデータアクセス(プロトタイピングおよび学習向け)
- プロトタイピングや学習、少人数のチームでリスクと対象法を認識している小さな製品向け
Server Only
import 'server-only';
- クライアントコンポーネントからモジュールのインポートを防ぐ
- クライアントへのデータ転送時のシリアライズは JSON のスーパーセットがサポートされている
- 秘匿データをそのままクライアントで使われないように JSON でシリアライズできない class オブジェクトを返すトリックが使える
- React Taint APIs を使うことでこのテクニックを使わなくてもクライアントでそのまま使われないようにすることができる(experimental)
- 秘匿データをそのままクライアントで使われないように JSON でシリアライズできない class オブジェクトを返すトリックが使える
- 上記を使っても完全に防ぐことはできないのでデータアクセスレイヤーを使用してリスクを最小限に抑えることができる[
SSR vs RSC
RSC はクライアントとは別のモジュールシステムで実行される。
SSRはブラウザクライアントと同じセキュリティーポリシーを適用し、特権データやプライベートAPIにアクセスすべきではない。
Read
データベースやAPIからのデータの読み込みは RSC のページをレンダリングすることで行う。
ページの入力として使われる searchParams、dynamic parameter、headerはクライアントによって改ざんされる可能性があるため、信頼せず毎回検証する必要がある。
アクセス制御と cookies() を読み直す。
Write
書き込みやミューテーションは server actions を使用する。
'use server' を使用することでエクスポートされたすべての関数をクライアントから呼び出せるようにするエンドポイントを公開する。
識別子はソースコードの場所のハッシュで、識別子を取得すれば任意の引数で関数を呼び出すことができるため、関数は常に現在のユーザーが実行可能か、各引数が問題ないか検証する必要がある。
Closures
Server Actions はクロージャーでエンコードすることができる。
これによって、レンダリング時のデータのスナップショットと関連づけて使用することができる。
closed over された変数はアクションID で暗号化され、秘密鍵はビルドのたびに新しく生成される。
そのため、各サーバーアクションはビルドされたバージョンでのみ呼び出すことが可能。
Skew Protection を使用して、再デプロ時に常に修正されたバージョンを呼び出すようにすると良い。
クロージャとは別の方法として、JavaScript の .bind 関数を使う方法がある。
これは暗号化せず、パフォーマンスのためのオプトアウトとして提供される。
CSRF
Server Actions は常に POST メソッドでのみ呼び出すことを許可されている。
モダンブラウザでは Same-Site Cookie がデフォルトなので CSRF 脆弱性を防ぐことができる。
Nextjs 14 の Server Action は Origin ヘッダーと Host ヘッダーを比較し、一致しない場合はアクションの実行が拒否される。
Server ActionsはCSRFトークンを使用しないため、HTMLのサニタイズは非常に重要です。
(CSRF トークンをしないことと HTML のサニタイズが重要なことのつながりがよくわからなかった)
カスタムルートハンドラ(route.ts)を使用する場合は、CSRF 保護を受動で行う必要がある。
Error Handling
Production モードではエラーやrejected promises はクライアントに送信せず、エラーを表すハッシュが送信される。
React はエラーメッセージを独自の汎用的なものに置き換える。
Custom Routes and Middleware
カスタムルートハンドラとミドルウェアは他の組み込み機能では実装できない機能のための低レベルな脱出口。
ミドルウェアを使用して特定のページへのアクセスを制限することができる。書き換えやクライアントからのリクエストなどの方法をすべて把握することは難しいため、許可リスト方式で行うのがベスト。
あるページへ上のサーバーアクションを制限するにはそのページの POST メソッドを禁止する。
Audit
- データアクセスレイヤー
- データアクセスレイヤーが分離されているか?
- データベースパッケージと環境変数がデータアクセスレイヤーの外部にインポートされていないか。
- use client ファイル
- コンポーネント・プロップがプライベート・データを期待していないか。型シグネチャの範囲が広すぎないか。
- use server ファイル
- アクションの引数はアクション内またはデータ・アクセス・レイヤ内で検証されていますか?
- ユーザはアクション内で再認証されていますか?
- /[param]/
- 括弧の付いたフォルダはユーザー入力です。paramはバリデートされていますか?
- middleware.tsxと route.tsxは大きな力を持っています
- 伝統的な手法を使って、これらの監査に特別な時間を費やす。
- 定期的に、あるいはチームのソフトウェア開発ライフサイクルに合わせて、侵入テストや脆弱性スキャンを実施する。