- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
11 KiB
11 KiB
CHIPS Cookies (Cookies Having Independent Partitioned State)
CHIPS Cookie-Unterstützung im Custom PHP Framework für datenschutzfreundliche Third-Party-Cookies.
Übersicht
CHIPS (Cookies Having Independent Partitioned State) ist ein Browser-Security-Feature, das Third-Party-Cookies pro Top-Level-Site partitioniert, um Cross-Site-Tracking zu verhindern.
Browser-Support:
- Chrome 114+
- Edge 114+
- Opera 100+
- Safari 16.4+ (partial)
Was ist CHIPS?
Problem: Traditional Third-Party Cookies
Widget embedded on example.com: cookie=user123
Same widget on test.com: cookie=user123 (SAME COOKIE!)
→ Cross-Site-Tracking möglich
Lösung: CHIPS Partitioned Cookies
Widget embedded on example.com: cookie=user123_site_A
Same widget on test.com: cookie=user456_site_B (DIFFERENT!)
→ Kein Cross-Site-Tracking
Requirements
CHIPS Cookies erfordern:
- Secure=true (HTTPS only)
- SameSite=None (Third-Party context)
- Partitioned Attribut
Verwendung
CookieService Injection
final readonly class EmbeddedWidgetController
{
public function __construct(
private CookieService $cookieService
) {}
}
Standard Cookie vs. CHIPS Cookie
// ❌ Standard Third-Party Cookie (tracking möglich)
$cookie = $this->cookieService->create(
name: 'analytics',
value: 'user123',
sameSite: SameSite::None,
secure: true
);
// ✅ CHIPS Partitioned Cookie (tracking verhindert)
$cookie = $this->cookieService->createPartitioned(
name: 'analytics',
value: 'user123'
);
Use Case 1: Embedded Chat Widget
#[Route(path: '/widget/chat/init', method: Method::GET)]
public function initChatWidget(HttpRequest $request): JsonResponse
{
$session = $this->chatService->createSession();
// Partitioned session cookie - different per embedding site
$sessionCookie = $this->cookieService->createPartitionedSession(
name: 'chat_session',
value: $session->id,
httpOnly: true
);
// Partitioned state cookie - JavaScript accessible
$stateCookie = $this->cookieService->createPartitioned(
name: 'chat_state',
value: json_encode(['minimized' => false]),
maxAge: Duration::fromDays(7),
httpOnly: false // JS needs access
);
return (new JsonResponse(['session_id' => $session->id]))
->withCookies($sessionCookie, $stateCookie);
}
Use Case 2: Third-Party Analytics
#[Route(path: '/analytics/track', method: Method::POST)]
public function track(HttpRequest $request): JsonResponse
{
$userId = $request->cookies->get('_analytics');
if (!$userId) {
// Create partitioned analytics cookie
$userId = $this->generateUserId();
$cookie = $this->cookieService->createAnalyticsCookie(
userId: $userId,
maxAge: Duration::fromDays(365)
);
return (new JsonResponse(['tracked' => true]))
->withCookie($cookie);
}
$this->analyticsService->track($userId, $request->parsedBody);
return new JsonResponse(['tracked' => true]);
}
Use Case 3: Payment Provider Embed
#[Route(path: '/payment/stripe/embed', method: Method::GET)]
public function embedPaymentForm(HttpRequest $request): ViewResult
{
$checkoutSession = $this->stripeService->createCheckoutSession();
// Partitioned - separate state per merchant site
$sessionCookie = $this->cookieService->createPartitioned(
name: 'stripe_checkout',
value: $checkoutSession->id,
maxAge: Duration::fromMinutes(30),
httpOnly: true
);
return (new ViewResult('payment/stripe-embed', [
'session' => $checkoutSession
]))->withCookie($sessionCookie);
}
CookieService Factory Methods
Standard Cookies
// Basic cookie
$cookie = $this->cookieService->create(
name: 'session',
value: 'abc123',
maxAge: Duration::fromHours(1),
path: '/',
domain: null,
secure: null, // Auto true in production
httpOnly: true,
sameSite: SameSite::Lax
);
// Session cookie (no expiration)
$cookie = $this->cookieService->createSessionCookie(
name: 'session_id',
value: 'xyz789',
httpOnly: true,
sameSite: SameSite::Lax
);
// Remember-me cookie (30 days default)
$cookie = $this->cookieService->createRememberMeCookie(
value: 'token123',
maxAge: Duration::fromDays(30) // Optional
);
// Delete cookie
$cookie = $this->cookieService->delete('session', path: '/');
CHIPS Partitioned Cookies
// Partitioned cookie
$cookie = $this->cookieService->createPartitioned(
name: 'widget',
value: 'state123',
maxAge: Duration::fromHours(1),
path: '/',
domain: null,
httpOnly: true
);
// Partitioned session cookie
$cookie = $this->cookieService->createPartitionedSession(
name: 'widget_session',
value: 'session123',
httpOnly: true
);
// Partitioned analytics cookie (JS accessible)
$cookie = $this->cookieService->createAnalyticsCookie(
userId: 'user123',
maxAge: Duration::fromDays(365)
);
// Partitioned widget state cookie
$cookie = $this->cookieService->createWidgetStateCookie(
widgetId: 'chat',
state: json_encode(['minimized' => false]),
maxAge: Duration::fromDays(30)
);
Response Integration
Single Cookie
return (new JsonResponse(['success' => true]))
->withCookie($cookie);
Multiple Cookies
return (new JsonResponse(['success' => true]))
->withCookies($sessionCookie, $stateCookie);
Validation & Helpers
// Validate cookie size (4KB browser limit)
if (!$this->cookieService->validateSize($cookie)) {
throw new \RuntimeException('Cookie exceeds size limit');
}
// Validate cookie name
if (!$this->cookieService->isValidName('user-token')) {
throw new \InvalidArgumentException('Invalid cookie name');
}
Cookie Header Output
Standard Cookie
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
CHIPS Partitioned Cookie
Set-Cookie: widget=state123; Path=/; Secure; HttpOnly; SameSite=None; Partitioned
Wann CHIPS verwenden?
✅ Use CHIPS für:
- Embedded Widgets - Chat, Support, Social Media embeds
- Third-Party Analytics - Analytics in iframes
- Payment Provider Embeds - Stripe, PayPal checkout forms
- OAuth Flows in iframes - Third-party authentication
- Cross-Origin Video Players - Embedded media players
❌ NICHT CHIPS für:
- First-Party Session Cookies - SameSite=Lax reicht
- Authentication Cookies - Nur same-site verwenden
- CSRF Tokens - SameSite=Strict empfohlen
- Standard E-Commerce - First-party cookies ausreichend
Security Best Practices
1. Production Environment
// Secure flag wird in production automatisch gesetzt
$prodEnv = new Environment([EnvKey::APP_ENV->value => 'production']);
$service = new CookieService($prodEnv);
$cookie = $service->create('session', 'value');
// → Secure flag automatisch true in production
2. HTTPS Required
CHIPS Cookies erfordern HTTPS:
// ✅ Wird in Cookie-Konstruktor validiert
$cookie = new Cookie(
name: 'widget',
value: 'data',
secure: true, // Required
sameSite: SameSite::None, // Required
partitioned: true
);
// ❌ Throws InvalidArgumentException
$cookie = new Cookie(
name: 'widget',
value: 'data',
secure: false, // Invalid!
partitioned: true
);
3. HttpOnly für Session Cookies
// ✅ HttpOnly für session cookies
$session = $this->cookieService->createPartitionedSession(
name: 'session',
value: 'secret',
httpOnly: true // XSS protection
);
// ❌ Nur wenn JS-Zugriff WIRKLICH notwendig
$widget = $this->cookieService->createPartitioned(
name: 'widget_state',
value: json_encode(['data']),
httpOnly: false // JS accessible
);
Testing
describe('CHIPS Cookie Integration', function () {
it('creates partitioned cookie for widget', function () {
$service = new CookieService($this->environment);
$cookie = $service->createPartitioned(
name: 'widget',
value: 'state123'
);
expect($cookie->partitioned)->toBeTrue();
expect($cookie->secure)->toBeTrue();
expect($cookie->sameSite)->toBe(SameSite::None);
$header = $cookie->toHeaderString();
expect($header)->toContain('Partitioned');
});
});
Framework Integration
DI Container Initializer
final readonly class CookieServiceInitializer
{
#[Initializer]
public function __invoke(Container $container): CookieService
{
return new CookieService(
environment: $container->get(Environment::class)
);
}
}
Response Trait (Future Enhancement)
trait ResponseWithCookies
{
private array $cookies = [];
public function withCookie(Cookie $cookie): self
{
$new = clone $this;
$new->cookies[] = $cookie;
return $new;
}
public function withCookies(Cookie ...$cookies): self
{
$new = clone $this;
$new->cookies = array_merge($new->cookies, $cookies);
return $new;
}
}
Migration von Standard Third-Party Cookies
Before (Traditional)
$cookie = new Cookie(
name: 'analytics',
value: 'user123',
secure: true,
sameSite: SameSite::None
);
// Problem: Cross-site tracking möglich
After (CHIPS)
$cookie = $this->cookieService->createPartitioned(
name: 'analytics',
value: 'user123'
);
// Benefit: Privacy-friendly, kein Cross-site tracking
Browser Compatibility Check (Future)
final readonly class ChipsSupportDetector
{
public function supportsChips(UserAgent $userAgent): bool
{
// Chrome/Edge 114+, Safari 16.4+, Opera 100+
return $this->detectBrowserVersion($userAgent);
}
public function getFallbackStrategy(): CookieStrategy
{
// First-party only, localStorage, etc.
return CookieStrategy::FIRST_PARTY_ONLY;
}
}
Troubleshooting
Cookie wird nicht gesetzt
- HTTPS fehlt: CHIPS erfordert Secure=true → HTTPS
- SameSite≠None: Muss
SameSite::Nonesein - Browser-Support: Prüfe Browser-Version
- Cookie-Size: Max 4KB - nutze
validateSize()
Cross-Site funktioniert nicht
- Partitioned fehlt: Nutze
createPartitioned()stattcreate() - Domain-Mismatch: Domain-Attribut korrekt setzen
- Path-Mismatch: Path muss übereinstimmen
Performance Considerations
- Cookie-Size: CHIPS Cookies zählen zum 4KB-Limit
- Anzahl Cookies: Browser-Limit beachten (typically 50-180)
- Expiration: Alte Cookies regelmäßig löschen
Zusammenfassung
CHIPS Cookies bieten: ✅ Privacy-Friendly - Kein Cross-Site-Tracking ✅ Framework-Compliant - Value Objects, Readonly, Type Safety ✅ Developer-Friendly - Einfache Factory Methods ✅ Production-Ready - Automatic Secure Flag, Validation ✅ Well-Tested - Comprehensive Pest Test Suite
Das Framework unterstützt CHIPS nativ für moderne, datenschutzfreundliche Third-Party-Integrationen.