Network Security
Flowstate’s network architecture is designed to minimize attack surface and protect sensitive communication. Services are isolated, communication is encrypted, and the backend is never directly exposed to the public internet.
Server-Side API Proxy
Section titled “Server-Side API Proxy”The web application uses a server-side proxy pattern for all backend API calls. Browsers never communicate directly with the backend:
Browser → Astro Server (/api/*) → Backend API (internal network)This architecture provides several critical security benefits.
Backend URL Remains Hidden
Section titled “Backend URL Remains Hidden”The backend API URL is never exposed to browsers. Client-side code uses relative URLs:
// Client-side code (runs in browser)const response = await fetch('/api/rooms', { credentials: 'include',});The Astro server receives the request at /api/rooms and forwards it to the backend on the internal network. The browser never sees the backend URL.
This prevents:
- Direct attacks: Attackers can’t bypass the proxy and attack the backend directly
- Information disclosure: The backend URL and port are not visible in network traffic
- Reconnaissance: Attackers can’t probe the backend to discover its structure
CORS Complexity Eliminated
Section titled “CORS Complexity Eliminated”Cross-Origin Resource Sharing (CORS) is a browser security feature that restricts which origins can make requests to an API. Configuring CORS correctly is complex and error-prone.
The proxy pattern eliminates CORS entirely. From the browser’s perspective, all requests go to the same origin (the Astro server). The browser never makes cross-origin requests, so CORS is not involved.
This simplifies the architecture and removes a common source of security misconfigurations.
Request Validation Server-Side
Section titled “Request Validation Server-Side”The Astro proxy validates requests before forwarding them to the backend:
- Authentication: Checks that the user is authenticated (valid session cookie)
- Authorization: Verifies the user has permission to access the requested resource
- Input validation: Validates query parameters and request bodies
- Rate limiting: Enforces rate limits before the request reaches the backend
If validation fails, the proxy returns an error response without forwarding the request. This reduces load on the backend and prevents invalid requests from reaching business logic.
Hop-by-Hop Headers Stripped
Section titled “Hop-by-Hop Headers Stripped”HTTP headers are classified as end-to-end or hop-by-hop. End-to-end headers are intended for the final recipient (the backend). Hop-by-hop headers are intended for the immediate recipient (the proxy).
The Astro proxy strips hop-by-hop headers before forwarding requests:
ConnectionKeep-AliveProxy-AuthenticateProxy-AuthorizationTETrailerTransfer-EncodingUpgrade
This prevents header-based attacks and ensures the backend only sees headers intended for it.
Production Backend is Internal-Only
Section titled “Production Backend is Internal-Only”In production, the backend API is not publicly accessible. It runs on an internal network (VPC, Docker network, or private subnet) and only accepts connections from the Astro server.
This architecture ensures:
- No direct access: Attackers can’t reach the backend from the internet
- Reduced attack surface: Only the Astro server is exposed to the public internet
- Defense in depth: Even if the Astro server is compromised, the backend is still protected by network isolation
RPC Gateway for Desktop and Mobile
Section titled “RPC Gateway for Desktop and Mobile”The Electron desktop app and future mobile clients use a separate RPC Gateway service. This public-facing service exposes only /rpc and /health endpoints.
Why a Separate Gateway?
Section titled “Why a Separate Gateway?”The backend REST API is designed for internal use by the web application. It has many endpoints, complex authentication flows, and tight coupling with the Astro server.
Desktop and mobile clients need a simpler, more stable API. The RPC Gateway provides:
- Stable interface: Connect RPC uses protocol buffers, which are versioned and backward-compatible
- Reduced attack surface: Only
/rpcand/healthare exposed (no admin endpoints, no file uploads, etc.) - Independent scaling: The gateway can scale independently of the backend
- Bearer token authentication: Desktop and mobile clients use Authorization headers, not cookies
Gateway Architecture
Section titled “Gateway Architecture”The RPC Gateway is a separate service that runs the same backend codebase with a different entrypoint:
Electron/Mobile → RPC Gateway (/rpc) → Backend (internal network)The gateway:
- Receives Connect RPC requests over HTTPS
- Validates the Bearer token in the Authorization header
- Forwards the request to the backend’s internal RPC handler
- Returns the response to the client
The gateway does not have direct database access. All data operations go through the backend’s internal services. This ensures business logic is centralized and consistent across all clients.
CORS for Public API
Section titled “CORS for Public API”The RPC Gateway allows all origins (Access-Control-Allow-Origin: *). This is safe because:
- Bearer token authentication: Requests must include a valid token in the Authorization header
- No cookies: The gateway doesn’t use cookies, so CSRF attacks are not possible
- Read-only for most operations: Most RPC calls are read-only (fetching data, not modifying it)
Allowing all origins simplifies client development. Desktop and mobile apps can make requests without CORS preflight checks.
Network Isolation
Section titled “Network Isolation”All services communicate via an internal network, not public IP addresses. Only the web server and RPC gateway are exposed to external traffic. The backend API, database, and cache are accessible only within the internal network.
Production Network Isolation
Section titled “Production Network Isolation”In production, services run in a VPC (Virtual Private Cloud) or equivalent network isolation:
- Web server: Public subnet, accessible from the internet
- RPC gateway: Public subnet, accessible from the internet
- Backend: Private subnet, only accessible from web server and gateway
- Database: Private subnet, only accessible from backend
- Redis: Private subnet, only accessible from backend
Network ACLs (Access Control Lists) enforce these restrictions at the network layer. Even if an attacker compromises the web server, they can’t directly access the database.
SSE Connection Security
Section titled “SSE Connection Security”Server-Sent Events (SSE) provide real-time updates from the backend to clients. SSE connections are long-lived HTTP connections that remain open for minutes or hours.
Authentication
Section titled “Authentication”SSE connections are authenticated:
- Web clients: Cookie authentication (same as regular API requests)
- Desktop clients: Bearer token in Authorization header
The backend validates authentication when the SSE connection is established. If authentication fails, the connection is rejected.
Heartbeat and Reconnection
Section titled “Heartbeat and Reconnection”SSE connections can be interrupted by network issues, proxy timeouts, or server restarts. Clients automatically reconnect when the connection is lost.
The backend sends periodic heartbeat messages to keep the connection alive:
: heartbeatIf the client doesn’t receive a heartbeat within 30 seconds, it assumes the connection is dead and reconnects.
Event Filtering
Section titled “Event Filtering”SSE events are filtered by user. Each user only receives events relevant to them:
- Canvas updates: Only updates to blocks the user owns
- Room messages: Only messages in rooms the user is a member of
- Notifications: Only notifications addressed to the user
The backend maintains a mapping of user ID to SSE connection. When an event occurs, the backend looks up the relevant users and sends the event to their connections.
Health Check Endpoints
Section titled “Health Check Endpoints”All services expose health check endpoints for monitoring:
| Service | Endpoint | Returns |
|---|---|---|
| Backend | /health | { status: "ok", database: "connected", redis: "connected" } |
| RPC Gateway | /health | { status: "ok" } |
| Web | /health | { status: "ok" } |
Health checks are exempt from rate limiting to ensure monitoring systems can always verify service availability.
Health Check Details
Section titled “Health Check Details”Backend health checks verify:
- Database connectivity: Attempts a simple query to MongoDB
- Redis connectivity: Attempts a PING command to Redis
- Service status: Returns 200 OK if all checks pass, 503 Service Unavailable if any check fails
Monitoring systems (like Kubernetes liveness probes or AWS health checks) use these endpoints to detect and restart unhealthy services.
Production Cookie Security
Section titled “Production Cookie Security”All production cookies use strict security settings:
res.cookie('session', token, { httpOnly: true, // Prevents JavaScript access secure: true, // HTTPS-only sameSite: 'lax', // CSRF protection maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days});httpOnly
Section titled “httpOnly”The httpOnly flag prevents JavaScript from accessing the cookie. This stops XSS (Cross-Site Scripting) attacks from stealing session tokens:
// This returns undefined for httpOnly cookiesdocument.cookie;Even if an attacker injects malicious JavaScript into the page, they can’t read the session cookie.
secure
Section titled “secure”The secure flag ensures cookies only transmit over HTTPS connections. This prevents man-in-the-middle attacks from intercepting session tokens.
If an attacker downgrades the connection to HTTP (for example, via a rogue Wi-Fi hotspot), the browser won’t send the cookie.
sameSite
Section titled “sameSite”The sameSite flag protects against CSRF (Cross-Site Request Forgery) attacks. With sameSite=lax, cookies are only sent for:
- Same-site requests: Requests from the same origin
- Top-level navigation: Clicking a link to the site
Cookies are not sent for:
- Cross-site POST requests: Forms submitted from other sites
- Cross-site AJAX requests: Fetch or XMLHttpRequest from other sites
This prevents attackers from tricking users into making authenticated requests from malicious sites.
Connection Security
Section titled “Connection Security”All external connections use encryption:
- HTTPS: Web and RPC traffic is encrypted with TLS 1.2 or higher
- MongoDB: Connections use TLS in production (optional in development)
- Redis: Connections use TLS in production (optional in development)
- S3: File uploads and downloads use HTTPS
TLS Configuration
Section titled “TLS Configuration”Production TLS configuration:
- Minimum version: TLS 1.2 (TLS 1.0 and 1.1 are disabled)
- Cipher suites: Only strong ciphers are allowed (no RC4, no 3DES)
- Certificate validation: Certificates must be valid and not expired
- HSTS: HTTP Strict Transport Security header forces HTTPS
HSTS tells browsers to always use HTTPS, even if the user types http:// in the address bar. This prevents downgrade attacks.
Redis Retry Strategy
Section titled “Redis Retry Strategy”Redis connections use a retry strategy to handle transient failures:
const redis = new Redis({ host: REDIS_HOST, port: REDIS_PORT, retryStrategy: (times) => { const delay = Math.min(times * 50, 2000); return delay; },});If Redis is unavailable, the client retries with exponential backoff (50ms, 100ms, 150ms, …, up to 2000ms). This handles:
- Temporary network issues: Brief connection drops
- Redis restarts: Service restarts during deployments
- Failover: Redis switching to a replica during primary failure
If Redis remains unavailable, rate limiting falls back to in-memory storage (per-instance, not shared). This ensures the application remains functional even if Redis is down.
MongoDB Replica Set
Section titled “MongoDB Replica Set”Production MongoDB uses a replica set for data integrity and high availability:
- Primary: Handles all writes
- Secondaries: Replicate data from the primary
- Automatic failover: If the primary fails, a secondary is promoted
Replica sets ensure:
- Data durability: Writes are replicated to multiple nodes before being acknowledged
- High availability: If one node fails, the others continue serving requests
- Read scaling: Read queries can be distributed across secondaries
The backend connects to the replica set using a connection string that lists all nodes and specifies the replica set name.
The MongoDB driver automatically discovers the primary and routes writes to it.
Network Security Checklist
Section titled “Network Security Checklist”Flowstate’s network security measures include:
- ✅ Server-side API proxy (backend URL never exposed to browsers)
- ✅ CORS eliminated (all requests are same-origin)
- ✅ Request validation (authentication, authorization, input validation)
- ✅ Hop-by-hop headers stripped (prevents header-based attacks)
- ✅ Production backend is internal-only (not publicly accessible)
- ✅ RPC Gateway (separate public-facing service for desktop/mobile)
- ✅ Network isolation (services communicate via internal network only)
- ✅ SSE authentication (cookie or Bearer token required)
- ✅ Health check endpoints (monitoring without authentication)
- ✅ httpOnly cookies (prevents XSS token theft)
- ✅ secure cookies (HTTPS-only transmission)
- ✅ sameSite cookies (CSRF protection)
- ✅ TLS encryption (all external connections use HTTPS)
- ✅ Redis retry strategy (handles transient failures)
- ✅ MongoDB replica set (data durability and high availability)
Future Network Security Enhancements
Section titled “Future Network Security Enhancements”Planned improvements:
- Web Application Firewall (WAF): Block common attack patterns (SQL injection, XSS, etc.)
- DDoS protection: Cloudflare or AWS Shield to absorb large-scale attacks
- IP allowlisting: Restrict admin access to specific IP ranges
- VPN access: Require VPN for internal services in production
- mTLS: Mutual TLS for service-to-service authentication
- Network segmentation: Separate networks for different service tiers
- Intrusion detection: Monitor network traffic for suspicious patterns
Network security is a continuous process. The platform evolves to address new threats and incorporate industry best practices.