Best Practices
Security

Security Best Practices

Guidelines for keeping your HiveForge application secure.

Authentication & Authorization

Use Strong Passwords

Enforce password requirements:

  • Minimum 12 characters
  • Mix of letters, numbers, symbols
  • Not in common password lists
// Configure in Supabase Dashboard
// Authentication > Settings > Password requirements

Enable MFA

Multi-factor authentication for sensitive accounts:

const { data, error } = await supabase.auth.mfa.enroll({
  factorType: 'totp',
})

Secure Session Management

  • Use HTTP-only cookies
  • Set appropriate session expiry
  • Implement refresh token rotation
// middleware.ts
const session = await supabase.auth.getSession()
 
if (!session || isExpired(session)) {
  await supabase.auth.refreshSession()
}

Implement RBAC

Use role-based access control:

function ProtectedAction() {
  const { hasPermission } = usePermissions()
 
  if (!hasPermission('organizations.delete')) {
    return null
  }
 
  return <DeleteButton />
}

Data Security

Row-Level Security (RLS)

Always enable RLS on tables:

ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY "Users view own organizations"
  ON organizations FOR SELECT
  USING (
    id IN (
      SELECT organization_id
      FROM organization_members
      WHERE user_id = auth.uid()
    )
  );

Input Validation

Validate all user input:

import { z } from 'zod'
 
const organizationSchema = z.object({
  name: z.string().min(1).max(100),
  slug: z.string().regex(/^[a-z0-9-]+$/),
  tier: z.enum(['free', 'pro', 'enterprise']),
})
 
// Validate input
const validated = organizationSchema.parse(input)

SQL Injection Prevention

Use parameterized queries:

# Bad - SQL injection risk
query = f"SELECT * FROM users WHERE email = '{email}'"
 
# Good - parameterized
result = await db.from_("users").select("*").eq("email", email).execute()

XSS Prevention

Sanitize user-generated content:

import DOMPurify from 'isomorphic-dompurify'
 
const sanitized = DOMPurify.sanitize(userInput)

API Security

Rate Limiting

Implement rate limits:

from slowapi import Limiter
from slowapi.util import get_remote_address
 
limiter = Limiter(key_func=get_remote_address)
 
@app.get("/api/endpoint")
@limiter.limit("100/minute")
async def endpoint():
    return {"status": "ok"}

CORS Configuration

Restrict origins:

from fastapi.middleware.cors import CORSMiddleware
 
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourdomain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["*"],
)

API Key Security

  • Hash API keys before storing
  • Use prefixes for identification
  • Implement scopes
  • Set expiration dates
import hashlib
 
def hash_api_key(key: str) -> str:
    return hashlib.sha256(key.encode()).hexdigest()
 
# Store hash, not raw key
await db.from_("api_keys").insert({
    "key_hash": hash_api_key(key),
    "key_prefix": key[:10],
})

Infrastructure

Environment Variables

  • Never commit secrets to git
  • Use different keys per environment
  • Rotate secrets regularly
  • Use secret management (Vault, AWS Secrets Manager)
# .gitignore
.env
.env.local
.env.production

HTTPS Only

Force HTTPS in production:

// middleware.ts
if (process.env.NODE_ENV === 'production' && !request.url.startsWith('https')) {
  return NextResponse.redirect(
    `https://${request.headers.get('host')}${request.url}`
  )
}

Security Headers

Set security headers:

// next.config.js
const securityHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on'
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload'
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
  {
    key: 'X-XSS-Protection',
    value: '1; mode=block'
  },
  {
    key: 'Referrer-Policy',
    value: 'strict-origin-when-cross-origin'
  },
  {
    key: 'Content-Security-Policy',
    value: "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline';"
  }
]

Monitoring & Logging

Audit Logging

Log security-relevant events:

async def log_security_event(
    user_id: str,
    action: str,
    resource: str,
    ip_address: str
):
    await db.from_("audit_logs").insert({
        "user_id": user_id,
        "action": action,
        "resource_type": resource,
        "ip_address": ip_address,
        "created_at": datetime.now()
    }).execute()

Error Handling

Don't leak sensitive info in errors:

# Bad - exposes internal details
raise HTTPException(
    status_code=500,
    detail=f"Database error: {str(db_error)}"
)
 
# Good - generic message
logger.error(f"Database error: {str(db_error)}")
raise HTTPException(
    status_code=500,
    detail="Internal server error"
)

Webhooks

Verify Signatures

Always verify webhook signatures:

import hmac
import hashlib
 
def verify_webhook_signature(
    payload: bytes,
    signature: str,
    secret: str
) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
 
    return hmac.compare_digest(signature, expected)

Dependencies

Regular Updates

Keep dependencies updated:

# Check for updates
pnpm outdated
 
# Update dependencies
pnpm update
 
# Check for security vulnerabilities
pnpm audit

Dependabot

Enable Dependabot for automatic security updates:

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

Compliance

GDPR

  • Get user consent for data processing
  • Allow data export
  • Implement right to be forgotten
  • Document data processing

Data Encryption

  • Encrypt data at rest
  • Use TLS for data in transit
  • Encrypt sensitive fields
  • Use encryption for backups

Incident Response

Security Checklist

When security incident occurs:

  1. Isolate affected systems
  2. Rotate all secrets
  3. Review audit logs
  4. Notify affected users
  5. Document incident
  6. Fix vulnerability
  7. Deploy fix
  8. Post-mortem

Key Rotation

Rotate secrets regularly:

# Rotate JWT secret
# 1. Generate new secret
openssl rand -base64 32
 
# 2. Update environment variables
# 3. Restart services
# 4. Invalidate old sessions

Testing Security

Security Tests

// Test authorization
test('rejects unauthorized access', async () => {
  const response = await fetch('/api/admin/users', {
    headers: { Authorization: 'Bearer invalid-token' }
  })
 
  expect(response.status).toBe(401)
})
 
// Test RLS
test('user cannot access other orgs', async () => {
  const { data } = await supabase
    .from('organizations')
    .select('*')
    .eq('id', 'other-org-id')
 
  expect(data).toHaveLength(0)
})

Security Checklist

  • Enable RLS on all tables
  • Validate all user input
  • Use HTTPS in production
  • Set security headers
  • Implement rate limiting
  • Hash API keys
  • Verify webhook signatures
  • Enable audit logging
  • Regular dependency updates
  • Strong password policy
  • MFA for admins
  • Error handling doesn't leak info
  • CORS properly configured
  • Secrets not in code
  • Regular security audits

Resources

Next Steps