15 — Security and Data Protection
PRD Document · Savoy Signature Hotels — Multi-Site Headless Platform
Version: 1.0 · Date: 2026-03-04
Related docs:02_Infrastructure_and_Environments.md,08_API_Contracts.md,12_Forms_and_Data_Collection.md
1. Purpose
Section titled “1. Purpose”This document outlines the security architecture for the Savoy Signature headless platform. It defines boundary protections, environment variables management, API security, automated scanning, and GDPR compliance.
2. Threat Model and Defense Layers
Section titled “2. Threat Model and Defense Layers”The headless architecture naturally mitigates many traditional CMS vulnerabilities by removing direct public access to the CMS database and backend code. However, new attack vectors (API abuse, unauthorized data exfiltration) must be secured.
2.1 Perimeter Defense (Cloudflare Pro)
Section titled “2.1 Perimeter Defense (Cloudflare Pro)”Cloudflare is the first line of defense for both the Next.js frontend and the Umbraco backend.
| Protection Layer | Configuration | Purpose |
|---|---|---|
| WAF (Web Application Firewall) | Cloudflare Managed Ruleset (Strict) | Blocks SQLi, XSS, and known CMS exploits before they reach Azure. |
| Bot Management | Super Bot Fight Mode (Enabled) | Challenges or blocks automated scrapers, form-fill bots, and vulnerability scanners. |
| Rate Limiting | 5 req/5min per IP on /api/forms/*; 20 req/min per IP on /api/search | Prevents denial-of-service and brute-force attacks on custom endpoints. |
| DDoS Protection | Unmetered L3/L4/L7 mitigation | Keeps the site online during volumetric attacks. |
| SSL/TLS | Full (Strict) | Enforces end-to-end encryption. Cloudflare issues edge certificates; Azure holds origin certificates. |
3. Umbraco CMS Security (Backend)
Section titled “3. Umbraco CMS Security (Backend)”The CMS is the ultimate source of truth and must be heavily insulated.
3.1 Network Isolation
Section titled “3.1 Network Isolation”- The Umbraco backoffice (
/umbraco) is not publicly accessible. - Cloudflare Zero Trust (Access) or Azure IP Restrictions lock down the backoffice URL to specific corporate IP addresses (e.g., WYcreative office, Savoy HR/Marketing VPNs).
- The Content Delivery API (
/umbraco/delivery/api/v2) is only accessible via the Next.js frontend origin.
3.2 Dev Auth Gate (Non-Production Environments)
Section titled “3.2 Dev Auth Gate (Non-Production Environments)”All non-production environments (DEV, Stage, QA) are protected by an authentication gate that blocks public access. Users must log in with Umbraco backoffice credentials before viewing any content.
| Feature | Implementation |
|---|---|
| Auth Method | Umbraco backoffice user credentials (email + password) |
| Token | JWT (__dev_gate cookie), signed with HMAC-SHA256 |
| TTL | 7 days |
| Cookie Scope | .wycreative.com (shared across all DEV subdomains) |
| Next.js | Middleware checks cookie; redirects to /gate/login if invalid |
| Storybook | Cloudflare Pages Function (_middleware.js) checks same cookie |
| Umbraco Endpoint | POST /api/auth/validate-backoffice (validates credentials, protected by X-Gate-Key header) |
| Production | Gate disabled (GATE_ENABLED=false) — sites are public |
| Exemptions | /api/health, /api/webhooks/*, /_next/static/* |
Spec: docs/superpowers/specs/2026-03-19-dev-auth-gate-design.md
3.3 Authentication and Authorization
Section titled “3.3 Authentication and Authorization”- Identity Provider: Umbraco uses Azure Active Directory (Microsoft Entra ID) via OpenID Connect. Local CMS accounts are disabled for all users except emergency admins.
- MFA: Multi-Factor Authentication is enforced at the Azure AD level for all editors.
- Role-Based Access Control (RBAC): Editors are restricted to specific hotel nodes. For example, a “Savoy Palace Editor” cannot edit “Royal Savoy” content.
3.4 Dependency Management
Section titled “3.4 Dependency Management”- Automated Scanning: GitHub Dependabot is enabled on the
apps/cmsrepository to scan NuGet packages for CVEs. - Patch Management: The CI/CD pipeline fails if high-severity vulnerabilities are detected during the
dotnet restorephase.
4. Next.js App Security (Frontend)
Section titled “4. Next.js App Security (Frontend)”The Node.js/React layer requires strict data handling and header configurations.
4.1 Security Headers
Section titled “4.1 Security Headers”The following headers are injected via next.config.ts:
// next.config.ts headers configurationconst securityHeaders = [ { key: 'X-DNS-Prefetch-Control', value: 'on' }, { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' }, { key: 'X-XSS-Protection', value: '1; mode=block' }, { key: 'X-Frame-Options', value: 'SAMEORIGIN' // Prevents clickjacking }, { key: 'X-Content-Type-Options', value: 'nosniff' // Prevents MIME-type sniffing }, { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }, { // Content Security Policy (CSP) key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com https://www.googletagmanager.com https://*.recaptcha.net; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://*.blob.core.windows.net https://savoysignature.com/cdn-cgi/image/; font-src 'self' data:; connect-src 'self' https://api.navarino.co https://*.google-analytics.com https://connect.facebook.net https://consent.cookiebot.com;" }];4.2 Secrets Management
Section titled “4.2 Secrets Management”Environment variables and connection strings are never committed to version control.
| Environment | Secrets Engine | Injection Method |
|---|---|---|
| Local | .env.local (git-ignored) | Next.js CLI / dotnet run |
| CI/CD | GitHub Actions Secrets | Passed to build context |
| Azure (All) | Azure Key Vault | App Services fetch secrets via Managed Identity at runtime. |
4.3 Client-Side Token Exposure
Section titled “4.3 Client-Side Token Exposure”- Tokens required by the browser (e.g.,
NEXT_PUBLIC_RECAPTCHA_SITE_KEY) are explicitly prefixed. - API keys for Umbraco (
UMBRACO_API_KEY), Cloudflare (CLOUDFLARE_API_TOKEN), and Mailjet are restricted to the Node.js context and never exposed to the client bundle.
5. Webhook Security
Section titled “5. Webhook Security”As defined in 08_API_Contracts.md, webhooks from Umbraco to Next.js (for cache purging) are secured via a shared secret.
- Umbraco hashes the payload with the
REVALIDATE_SECRETand sends anX-Webhook-Signatureheader. - Next.js computes the HMAC SHA-256 signature of the received payload using the same secret.
- If signatures match, the payload is trusted. Furthermore, the webhook endpoint enforces a strict IP allowlist (accepting requests only from the Umbraco Azure App Service IP).
6. Data Protection & GDPR
Section titled “6. Data Protection & GDPR”Savoy Signature processes PII (Personally Identifiable Information) via forms and analytics.
6.1 Data at Rest & in Transit
Section titled “6.1 Data at Rest & in Transit”- At Rest: The Azure SQL database (Umbraco content/forms) and Azure Blob Storage (media/uploads) utilize TDE (Transparent Data Encryption) with Microsoft-managed keys.
- In Transit: All traffic is mandated over TLS 1.3 (fallback 1.2).
6.2 Data Minimization & Retention
Section titled “6.2 Data Minimization & Retention”- Form Submissions: Stored in Umbraco Forms to handle email failure retries. Auto-deleted via a scheduled task after 90 days (configurable per form).
- Log Data: Azure Application Insights retains application logs for 90 days. Log payloads are stripped of request bodies (e.g., passwords, credit card info).
6.3 Cookie Consent (Cookiebot)
Section titled “6.3 Cookie Consent (Cookiebot)”The platform utilizes Cookiebot.com as the official Consent Management Platform (CMP).
- Implementation: The Cookiebot script (
<script id="Cookiebot" ...>) is injected into the<head>of thelayout.tsxfile for all 8 sites. - Auto-blocking: Cookiebot’s automatic cookie blocking prevents GTM, Navarino tracking, and other third-party scripts from executing before explicit user consent is granted.
- Exemptions: Essential cookies (e.g., Next.js locale routing, CSRF tokens, Cloudflare protection tokens) are classified strictly non-tracking and exempt from blocking.
- Alerts/Audits: The DPO receives monthly automated scan reports from Cookiebot. Unclassified cookies trigger an alert requiring manual categorization by the dev team.
7. Acceptance Criteria
Section titled “7. Acceptance Criteria”- Cloudflare WAF is blocking known exploits across all domains.
- Umbraco backoffice is inaccessible from unauthorized IP addresses.
- Next.js HTTP response headers achieve an “A” grade on SecurityHeaders.com.
- No secrets or API keys are present in the frontend bundle (verified via bundle analysis).
- Webhook cache purge endpoints require a valid cryptographic signature.
- Form payloads containing PII are encrypted at rest and auto-erased after 90 days.
- Azure Key Vault is successfully utilized for all production secrets via Managed Identity.
Next document: 16_Analytics_and_Tracking.md