Skip to content

Security Best Practices

Security Best Practices

Input Sanitization

Never render user input as HTML:

// NEVER do this
<div dangerouslySetInnerHTML={{ __html: userContent }} />

// If you must render HTML, sanitize it
import DOMPurify from 'dompurify';

function SafeHtml({ html }: { html: string }) {
  const sanitized = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
    ALLOWED_ATTR: ['href'],
  });

  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}

Environment Variables

Understand what gets exposed:

# Server-only (never sent to browser)
DATABASE_URL=postgresql://...
API_SECRET=...

# Public (bundled into client code)
NEXT_PUBLIC_API_URL=https://api.sartiq.com
NEXT_PUBLIC_APP_URL=https://app.sartiq.com

Rule: Never put secrets in NEXT_PUBLIC_* variables.

XSS Prevention

// URLs - validate before using
function SafeLink({ url }: { url: string }) {
  const isValid = url.startsWith('https://') || url.startsWith('/');
  if (!isValid) return null;
  return <a href={url}>Link</a>;
}

// User content - escape by default (React does this)
<p>{userInput}</p> // Safe - React escapes

// JSON in script tags - use proper encoding
<script
  type="application/json"
  dangerouslySetInnerHTML={{
    __html: JSON.stringify(data).replace(/</g, '\\u003c')
  }}
/>

See Also

  • OWASP Top 10 -- Comprehensive overview of web application security risks
  • Input Validation -- Server-side and client-side validation to prevent injection attacks