CRUD機能のあるSaaSのセキュリティ対策まとめ
SaaS開発、特に複数顧客が同一データベースを利用するマルチテナントアーキテクチャにおいて、セキュリティの担保は事業継続の最重要課題です。本記事では、システムを複数層で防御する設計思想と、リリース初期に優先すべき実装レベルの対策を客観的な事実に基づいて解説します。
1. 認証と認可の分離・堅牢化
「誰がシステムに入るか(認証)」と「誰がどのデータを見れるか(認可)」は分けて設計します。
認証 (Authentication)
- 対策: Auth0、AWS Cognito、Firebase Authなどのマネージドサービスを利用します。
- 理由: 認証基盤(パスワードハッシュ化、MFA、セッション管理など)の自前実装は脆弱性を生むリスクが高いため、セキュリティ水準が担保された外部プロバイダーに委託することが最も合理的です。
認可 (Authorization): 行レベルセキュリティ(RLS)
- 概念: アプリケーション側(GoやNext.jsなど)のコードでアクセス制御を行うのではなく、データベース(PostgreSQL)側で設定する強制的なアクセス制御機能です。
- 仕組み: DBエンジンが「ログイン中のユーザーIDと一致する行(Row)だけを返す」というルール(ポリシー)を評価します。
-
メリット: アプリケーション側で
WHERE tenant_id = ?のような絞り込み条件を書き忘れる実装漏れ(ヒューマンエラー)が発生しても、DB層で情報の流出を物理的に防ぐことができます。
| 項目 | アプリケーション層フィルタリング | RLS (PostgreSQL等) |
|---|---|---|
| 制御場所 | Go / Next.js のコード内 | データベースエンジン内部 |
| 実装例 | SELECT * FROM table WHERE tenant_id = 'A' |
CREATE POLICY ... USING (tenant_id = 'A') |
| ヒューマンエラー |
WHERE 句を書き忘れると全データが漏洩する |
SELECT * FROM table と書いても自動で絞り込まれる |
| ユニークキー | 主にインデックスや検索のために使用 | ポリシーの判定基準(所有者ID等)として使用 |
2. インフラとアプリケーションの多層防御
Webアプリケーションに対する一般的な攻撃には、境界防御と内部ロジックの両面から対処します。
WAF (Web Application Firewall) による境界防御
- 役割: Cloudflare等のWAFを導入し、アプリケーションにリクエストが到達する前に、既知の攻撃シグネチャ(SQLインジェクションやXSSのパターン)を含む通信を遮断します。
アプリケーションの処理ロジックによる根本対策
WAFはあくまで「外壁」であり、処理側での対策が必須です。
-
SQLインジェクション対策: Goの
database/sqlやORMで提供される**プレースホルダ(バインド変数)**を必ず使用します。外部からの入力値をSQLの「命令」ではなく「文字列データ」として処理させることで、不正なSQLの実行を無効化します。文字列連結によるクエリの生成は一切禁止します。 - XSS対策: Next.jsなどのモダンなフレームワークが提供するデフォルトのエスケープ処理を利用し、ユーザー入力をそのままHTMLとして描画しない設計を徹底します。
3. 通信とデータの保護
保存されているデータと、ネットワーク上を流れるデータの両方を保護します。
保存時の暗号化 (Data at Rest)
- 対策: AWS RDS(データベース)やCloudflare R2(オブジェクトストレージ)が提供するデフォルトの暗号化機能を有効化し、ディスク上のデータを保護します。
転送時の暗号化とHSTS (Data in Transit)
全経路でのTLS化(HTTPS)を前提とした上で、ダウングレード攻撃(中間者が強制的にHTTP通信へ格下げして盗聴する攻撃)を防ぎます。
- HSTS (HTTP Strict Transport Security) の概念: サーバーからブラウザに対して「今後は強制的にHTTPSで通信せよ」と命令する仕組みです。
-
対策(設定方法): 1. Webサーバー(Next.jsのミドルウェアなど)のレスポンスに以下のHTTPヘッダーを付与します。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- または、Cloudflareの管理画面(SSL/TLS設定)から「HSTSを有効化」の設定をオンにします。
-
確認方法: Chromeのアドレスバーに
chrome://net-internals/#hstsと入力し、「Query HSTS/PKP domain」に自身のドメインを入力して検索することで、ブラウザに設定が反映されているか確認できます。
4. Go / Next.js における実装レベルの具体的対策
| 項目 | 対策内容 |
|---|---|
| SQLインジェクション | GoのORM(GORM等)や database/sql のプレースホルダ(バインド変数)を必ず使用し、生クエリの文字列連結によるSQL実行を禁止する。 |
| XSS対策 | Next.jsが提供するデフォルトのエスケープ処理に依存し、dangerouslySetInnerHTML のようなユーザー入力を直接DOMに描画する実装を避ける。 |
| CSRF対策 | Next.js(App Router)のServer Actions利用時はフレームワーク標準の保護機能を利用し、Goで構築したカスタムAPIエンドポイントにはCSRFトークンによる検証を独自に実装する。 |
| シークレット管理 | APIキーやDBのパスワード等の機密情報をソースコードにハードコーディングせず、AWS Secrets Manager等を利用して実行時に環境変数として注入する。 |
| 依存関係の脆弱性管理 | CI/CDパイプラインに gosec、npm audit、または GitHub Dependabot を組み込み、既知の脆弱性を持つ外部ライブラリの混入を自動的に遮断する。 |
5. リリース初期の「最小限の守り」とリスクマネジメント
SaaSの初期リリースにおいて、セキュリティへの不安を完全にゼロにすることは不可能です。ビジネスでは「リスクの許容とコントロール」が求められます。
- 事実: 100%安全なシステムは存在しません。
- 対策(検知と復旧の仕組み): 侵害されることを前提とし、バックアップの自動取得・定期的なリストアテストと、操作ログの監視体制を構築します。
- 結論: これらを整備することで、心理的な「不安」を、事後対応が可能な「技術的なコントロール」へと置き換えることができます。