スキル一覧に戻る
lenneTech

general-frontend-security

by lenneTech

Claude Code Plugin for lenne.tech development - Skills, Commands & Hooks for Nuxt 4, NestJS, TDD and CLI tools

0🍴 0📅 2026年1月19日
GitHubで見るManusで実行

SKILL.md


name: general-frontend-security description: Framework-agnostic frontend security guide based on OWASP. Use when implementing security in web applications, reviewing frontend code for vulnerabilities, or working with client-side authentication, XSS prevention, CSRF protection, or secure storage. Covers browser security features, client-side validation, and security headers.

General Frontend Security

Framework-agnostic security practices for web applications based on OWASP guidelines.

When to Use This Skill

  • Reviewing frontend code for security vulnerabilities
  • Implementing client-side authentication flows
  • Setting up secure cookie handling
  • Configuring Content Security Policy
  • Auditing third-party dependencies
  • General frontend security questions

Framework-Specific References


OWASP Top 10 for Frontend

1. Cross-Site Scripting (XSS)

Prevention:

// ❌ DANGEROUS: innerHTML with user input
element.innerHTML = userInput

// ✅ SAFE: textContent for plain text
element.textContent = userInput

// ✅ SAFE: Sanitize if HTML needed
import DOMPurify from 'dompurify'
element.innerHTML = DOMPurify.sanitize(userInput)

Types of XSS:

  • Stored XSS: Malicious script stored in database, served to users
  • Reflected XSS: Script in URL parameters reflected in response
  • DOM-based XSS: Script manipulates DOM directly

2. Broken Authentication

Prevention:

  • Use httpOnly cookies for session tokens
  • Implement token refresh with short-lived access tokens
  • Never store sensitive tokens in localStorage
  • Implement proper logout (server-side token invalidation)

3. Sensitive Data Exposure

Prevention:

  • Never log passwords, tokens, or PII to console
  • Don't store sensitive data in client-side state
  • Use HTTPS for all API communication
  • Mask sensitive input fields

4. Broken Access Control

Prevention:

  • Client-side access control is UI-only (server must verify)
  • Validate redirects against allowlist
  • Don't expose admin features based on client-side flags

5. Security Misconfiguration

Prevention:

  • Configure CSP headers properly
  • Disable debug mode in production
  • Remove development tools and console logs
  • Use secure cookie flags

Client-Side Storage Security

localStorage/sessionStorage

// ❌ NEVER store in localStorage:
// - Access tokens
// - Refresh tokens
// - Session IDs
// - Credit card numbers
// - Passwords

// localStorage is accessible to any script (XSS vulnerable)
localStorage.setItem('token', sensitiveToken)  // DANGEROUS

// ⚠️ Use only for non-sensitive data
localStorage.setItem('theme', 'dark')  // OK
localStorage.setItem('language', 'de')  // OK

Secure Token Storage Options

MethodXSS RiskCSRF RiskRecommendation
localStorageHIGHNoneNever for tokens
sessionStorageHIGHNoneNever for tokens
httpOnly CookieNoneMediumBest for refresh tokens
Memory (JS variable)LowNoneGood for access tokens
Secure Cookie (non-httpOnly)MediumMediumAvoid
// Access token: Store in memory (cleared on page refresh)
let accessToken = null

function setAccessToken(token) {
  accessToken = token
}

function getAccessToken() {
  return accessToken
}

// Refresh token: httpOnly cookie (set by server)
// Frontend never sees it, automatically sent with requests
async function refreshAccessToken() {
  const response = await fetch('/api/auth/refresh', {
    method: 'POST',
    credentials: 'include'  // Send httpOnly cookie
  })
  const { accessToken } = await response.json()
  setAccessToken(accessToken)
}

Browser Security Features

Content Security Policy (CSP)

<!-- HTTP Header (recommended) or meta tag -->
<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' 'nonce-abc123';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  font-src 'self';
  object-src 'none';
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
">

Key Directives:

DirectivePurposeRecommendation
default-srcFallback for all'self'
script-srcJavaScript sources'self' + nonces
style-srcCSS sources'self' (avoid 'unsafe-inline')
img-srcImage sources'self' data: https:
connect-srcXHR/Fetch/WebSocketExplicit API origins
frame-ancestorsWho can embed'none' (prevent clickjacking)

Subresource Integrity (SRI)

<!-- Always use SRI for external scripts/styles -->
<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

Security Headers

# Prevent clickjacking
X-Frame-Options: DENY

# Prevent MIME sniffing
X-Content-Type-Options: nosniff

# Enforce HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

# Control referrer information
Referrer-Policy: strict-origin-when-cross-origin

# Restrict feature access
Permissions-Policy: geolocation=(), camera=(), microphone=()

// Server sets cookies with these flags
Set-Cookie: sessionId=abc123;
  HttpOnly;       // Not accessible via JavaScript (XSS protection)
  Secure;         // Only sent over HTTPS
  SameSite=Strict;  // Not sent with cross-site requests (CSRF protection)
  Path=/;         // Cookie scope
  Max-Age=86400   // Expiry (in seconds)
FlagPurposeWhen to Use
HttpOnlyPrevent JS accessAlways for session/auth cookies
SecureHTTPS onlyAlways in production
SameSite=StrictNo cross-siteAuth cookies, most secure
SameSite=LaxSome cross-siteDefault, allows GET navigation
SameSite=NoneAll cross-siteThird-party cookies (requires Secure)

Input Validation

Client-Side Validation (UI Only)

// Client validation improves UX but NEVER trust it for security
function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  return regex.test(email)
}

function validatePassword(password) {
  return password.length >= 8 &&
         /[A-Z]/.test(password) &&
         /[a-z]/.test(password) &&
         /[0-9]/.test(password)
}

// Always validate on server too!

URL Validation

function isValidUrl(url) {
  try {
    const parsed = new URL(url)
    return ['http:', 'https:'].includes(parsed.protocol)
  } catch {
    return false
  }
}

function isSameOrigin(url) {
  try {
    const parsed = new URL(url, window.location.origin)
    return parsed.origin === window.location.origin
  } catch {
    return false
  }
}

// Redirect validation
function safeRedirect(url) {
  if (isSameOrigin(url) || ALLOWED_EXTERNAL_ORIGINS.includes(new URL(url).origin)) {
    window.location.href = url
  } else {
    window.location.href = '/dashboard'  // Fallback
  }
}

File Upload Validation

const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'application/pdf']
const MAX_SIZE = 5 * 1024 * 1024  // 5MB

function validateFile(file) {
  const errors = []

  if (!ALLOWED_TYPES.includes(file.type)) {
    errors.push('Invalid file type')
  }

  if (file.size > MAX_SIZE) {
    errors.push('File too large (max 5MB)')
  }

  // Check file extension matches type
  const ext = file.name.split('.').pop()?.toLowerCase()
  const expectedExts = {
    'image/jpeg': ['jpg', 'jpeg'],
    'image/png': ['png'],
    'application/pdf': ['pdf']
  }

  if (expectedExts[file.type] && !expectedExts[file.type].includes(ext)) {
    errors.push('File extension mismatch')
  }

  return errors
}

API Security

Secure Fetch Wrapper

async function secureFetch(url, options = {}) {
  const config = {
    ...options,
    credentials: 'include',  // Include cookies
    headers: {
      'Content-Type': 'application/json',
      ...options.headers
    }
  }

  // Add CSRF token for state-changing requests
  if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(options.method)) {
    const csrfToken = getCsrfToken()  // From cookie or meta tag
    if (csrfToken) {
      config.headers['X-CSRF-Token'] = csrfToken
    }
  }

  try {
    const response = await fetch(url, config)

    if (response.status === 401) {
      // Token expired - try refresh or redirect to login
      await handleUnauthorized()
      return null
    }

    if (!response.ok) {
      // Don't expose error details to users
      console.error('API Error:', response.status)
      throw new Error('Request failed')
    }

    return response.json()
  } catch (error) {
    // Log for debugging, show generic message to user
    console.error('Fetch error:', error)
    throw new Error('Network error')
  }
}

Rate Limiting Awareness

class RateLimitedClient {
  private retryAfter = 0

  async request(url, options) {
    if (Date.now() < this.retryAfter) {
      throw new Error('Rate limited. Please wait.')
    }

    const response = await fetch(url, options)

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After')
      this.retryAfter = Date.now() + (parseInt(retryAfter || '60') * 1000)
      throw new Error('Too many requests. Please try again later.')
    }

    return response
  }
}

Third-Party Dependencies

Audit Process

# Check for vulnerabilities
npm audit

# Auto-fix where safe
npm audit fix

# Check outdated packages
npm outdated

# Update to latest (careful with major versions)
npm update

Dependency Best Practices

  1. Lock versions: Always commit package-lock.json
  2. Regular audits: Run npm audit in CI/CD
  3. Minimal dependencies: Fewer deps = smaller attack surface
  4. Review before adding: Check package popularity, maintenance, and security
  5. CDN integrity: Always use SRI for CDN resources

DevTools Security

Production Safeguards

// Remove console statements in production build
// Most bundlers support this via configuration

// Disable right-click (not a security measure, just UX)
// Don't rely on this for security!

// Detect DevTools (not reliable, just awareness)
// Not a security measure - determined attackers bypass this

// REAL security: Proper server-side validation and authentication

Security Checklist

Development

  • No sensitive data in client-side code
  • Environment variables separated (public vs private)
  • Input validation on all user inputs
  • XSS prevention (no innerHTML with user data)
  • CSRF tokens for state-changing requests

Authentication

  • Tokens stored securely (memory + httpOnly cookies)
  • Token refresh mechanism implemented
  • Proper logout (clear all client state)
  • Session timeout configured

Configuration

  • HTTPS enforced
  • CSP headers configured
  • Security headers set (X-Frame-Options, etc.)
  • Cookies configured with secure flags
  • CORS properly restricted

Dependencies

  • npm audit clean (or accepted risks)
  • package-lock.json committed
  • SRI for external resources
  • Regular dependency updates

Build & Deploy

  • Debug mode disabled
  • Console logs removed
  • Source maps disabled or restricted
  • Error messages generic (no stack traces)

スコア

総合スコア

75/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

レビュー

💬

レビュー機能は近日公開予定です