[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-5375a30e-5086-41bb-808a-4aec34d67fbf":3,"$fUVtCDF8VVw3qkMHcdAduggoJhYCM-ESh-Az35-scpic":42},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":33},"5375a30e-5086-41bb-808a-4aec34d67fbf","api-security-best-practices","实现安全的API设计模式，包括身份验证、授权、输入验证、速率限制以及防范常见的API漏洞","cat_coding_backend","mod_coding","sickn33,coding","---\nname: api-security-best-practices\ndescription: \"Implement secure API design patterns including authentication, authorization, input validation, rate limiting, and protection against common API vulnerabilities\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# API Security Best Practices\n\n## Overview\n\nGuide developers in building secure APIs by implementing authentication, authorization, input validation, rate limiting, and protection against common vulnerabilities. This skill covers security patterns for REST, GraphQL, and WebSocket APIs.\n\n## When to Use This Skill\n\n- Use when designing new API endpoints\n- Use when securing existing APIs\n- Use when implementing authentication and authorization\n- Use when protecting against API attacks (injection, DDoS, etc.)\n- Use when conducting API security reviews\n- Use when preparing for security audits\n- Use when implementing rate limiting and throttling\n- Use when handling sensitive data in APIs\n\n## How It Works\n\n### Step 1: Authentication & Authorization\n\nI'll help you implement secure authentication:\n- Choose authentication method (JWT, OAuth 2.0, API keys)\n- Implement token-based authentication\n- Set up role-based access control (RBAC)\n- Secure session management\n- Implement multi-factor authentication (MFA)\n\n### Step 2: Input Validation & Sanitization\n\nProtect against injection attacks:\n- Validate all input data\n- Sanitize user inputs\n- Use parameterized queries\n- Implement request schema validation\n- Prevent SQL injection, XSS, and command injection\n\n### Step 3: Rate Limiting & Throttling\n\nPrevent abuse and DDoS attacks:\n- Implement rate limiting per user\u002FIP\n- Set up API throttling\n- Configure request quotas\n- Handle rate limit errors gracefully\n- Monitor for suspicious activity\n\n### Step 4: Data Protection\n\nSecure sensitive data:\n- Encrypt data in transit (HTTPS\u002FTLS)\n- Encrypt sensitive data at rest\n- Implement proper error handling (no data leaks)\n- Sanitize error messages\n- Use secure headers\n\n### Step 5: API Security Testing\n\nVerify security implementation:\n- Test authentication and authorization\n- Perform penetration testing\n- Check for common vulnerabilities (OWASP API Top 10)\n- Validate input handling\n- Test rate limiting\n\n\n## Examples\n\n### Example 1: Implementing JWT Authentication\n\n```markdown\n## Secure JWT Authentication Implementation\n\n### Authentication Flow\n\n1. User logs in with credentials\n2. Server validates credentials\n3. Server generates JWT token\n4. Client stores token securely\n5. Client sends token with each request\n6. Server validates token\n\n### Implementation\n\n#### 1. Generate Secure JWT Tokens\n\n\\`\\`\\`javascript\n\u002F\u002F auth.js\nconst jwt = require('jsonwebtoken');\nconst bcrypt = require('bcrypt');\n\n\u002F\u002F Login endpoint\napp.post('\u002Fapi\u002Fauth\u002Flogin', async (req, res) => {\n  try {\n    const { email, password } = req.body;\n    \n    \u002F\u002F Validate input\n    if (!email || !password) {\n      return res.status(400).json({ \n        error: 'Email and password are required' \n      });\n    }\n    \n    \u002F\u002F Find user\n    const user = await db.user.findUnique({ \n      where: { email } \n    });\n    \n    if (!user) {\n      \u002F\u002F Don't reveal if user exists\n      return res.status(401).json({ \n        error: 'Invalid credentials' \n      });\n    }\n    \n    \u002F\u002F Verify password\n    const validPassword = await bcrypt.compare(\n      password, \n      user.passwordHash\n    );\n    \n    if (!validPassword) {\n      return res.status(401).json({ \n        error: 'Invalid credentials' \n      });\n    }\n    \n    \u002F\u002F Generate JWT token\n    const token = jwt.sign(\n      { \n        userId: user.id,\n        email: user.email,\n        role: user.role\n      },\n      process.env.JWT_SECRET,\n      { \n        expiresIn: '1h',\n        issuer: 'your-app',\n        audience: 'your-app-users'\n      }\n    );\n    \n    \u002F\u002F Generate refresh token\n    const refreshToken = jwt.sign(\n      { userId: user.id },\n      process.env.JWT_REFRESH_SECRET,\n      { expiresIn: '7d' }\n    );\n    \n    \u002F\u002F Store refresh token in database\n    await db.refreshToken.create({\n      data: {\n        token: refreshToken,\n        userId: user.id,\n        expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)\n      }\n    });\n    \n    res.json({\n      token,\n      refreshToken,\n      expiresIn: 3600\n    });\n    \n  } catch (error) {\n    console.error('Login error:', error);\n    res.status(500).json({ \n      error: 'An error occurred during login' \n    });\n  }\n});\n\\`\\`\\`\n\n#### 2. Verify JWT Tokens (Middleware)\n\n\\`\\`\\`javascript\n\u002F\u002F middleware\u002Fauth.js\nconst jwt = require('jsonwebtoken');\n\nfunction authenticateToken(req, res, next) {\n  \u002F\u002F Get token from header\n  const authHeader = req.headers['authorization'];\n  const token = authHeader && authHeader.split(' ')[1]; \u002F\u002F Bearer TOKEN\n  \n  if (!token) {\n    return res.status(401).json({ \n      error: 'Access token required' \n    });\n  }\n  \n  \u002F\u002F Verify token\n  jwt.verify(\n    token, \n    process.env.JWT_SECRET,\n    { \n      issuer: 'your-app',\n      audience: 'your-app-users'\n    },\n    (err, user) => {\n      if (err) {\n        if (err.name === 'TokenExpiredError') {\n          return res.status(401).json({ \n            error: 'Token expired' \n          });\n        }\n        return res.status(403).json({ \n          error: 'Invalid token' \n        });\n      }\n      \n      \u002F\u002F Attach user to request\n      req.user = user;\n      next();\n    }\n  );\n}\n\nmodule.exports = { authenticateToken };\n\\`\\`\\`\n\n#### 3. Protect Routes\n\n\\`\\`\\`javascript\nconst { authenticateToken } = require('.\u002Fmiddleware\u002Fauth');\n\n\u002F\u002F Protected route\napp.get('\u002Fapi\u002Fuser\u002Fprofile', authenticateToken, async (req, res) => {\n  try {\n    const user = await db.user.findUnique({\n      where: { id: req.user.userId },\n      select: {\n        id: true,\n        email: true,\n        name: true,\n        \u002F\u002F Don't return passwordHash\n      }\n    });\n    \n    res.json(user);\n  } catch (error) {\n    res.status(500).json({ error: 'Server error' });\n  }\n});\n\\`\\`\\`\n\n#### 4. Implement Token Refresh\n\n\\`\\`\\`javascript\napp.post('\u002Fapi\u002Fauth\u002Frefresh', async (req, res) => {\n  const { refreshToken } = req.body;\n  \n  if (!refreshToken) {\n    return res.status(401).json({ \n      error: 'Refresh token required' \n    });\n  }\n  \n  try {\n    \u002F\u002F Verify refresh token\n    const decoded = jwt.verify(\n      refreshToken, \n      process.env.JWT_REFRESH_SECRET\n    );\n    \n    \u002F\u002F Check if refresh token exists in database\n    const storedToken = await db.refreshToken.findFirst({\n      where: {\n        token: refreshToken,\n        userId: decoded.userId,\n        expiresAt: { gt: new Date() }\n      }\n    });\n    \n    if (!storedToken) {\n      return res.status(403).json({ \n        error: 'Invalid refresh token' \n      });\n    }\n    \n    \u002F\u002F Generate new access token\n    const user = await db.user.findUnique({\n      where: { id: decoded.userId }\n    });\n    \n    const newToken = jwt.sign(\n      { \n        userId: user.id,\n        email: user.email,\n        role: user.role\n      },\n      process.env.JWT_SECRET,\n      { expiresIn: '1h' }\n    );\n    \n    res.json({\n      token: newToken,\n      expiresIn: 3600\n    });\n    \n  } catch (error) {\n    res.status(403).json({ \n      error: 'Invalid refresh token' \n    });\n  }\n});\n\\`\\`\\`\n\n### Security Best Practices\n\n- ✅ Use strong JWT secrets (256-bit minimum)\n- ✅ Set short expiration times (1 hour for access tokens)\n- ✅ Implement refresh tokens for long-lived sessions\n- ✅ Store refresh tokens in database (can be revoked)\n- ✅ Use HTTPS only\n- ✅ Don't store sensitive data in JWT payload\n- ✅ Validate token issuer and audience\n- ✅ Implement token blacklisting for logout\n```\n\n\n### Example 2: Input Validation and SQL Injection Prevention\n\n```markdown\n## Preventing SQL Injection and Input Validation\n\n### The Problem\n\n**❌ Vulnerable Code:**\n\\`\\`\\`javascript\n\u002F\u002F NEVER DO THIS - SQL Injection vulnerability\napp.get('\u002Fapi\u002Fusers\u002F:id', async (req, res) => {\n  const userId = req.params.id;\n  \n  \u002F\u002F Dangerous: User input directly in query\n  const query = \\`SELECT * FROM users WHERE id = '\\${userId}'\\`;\n  const user = await db.query(query);\n  \n  res.json(user);\n});\n\n\u002F\u002F Attack example:\n\u002F\u002F GET \u002Fapi\u002Fusers\u002F1' OR '1'='1\n\u002F\u002F Returns all users!\n\\`\\`\\`\n\n### The Solution\n\n#### 1. Use Parameterized Queries\n\n\\`\\`\\`javascript\n\u002F\u002F ✅ Safe: Parameterized query\napp.get('\u002Fapi\u002Fusers\u002F:id', async (req, res) => {\n  const userId = req.params.id;\n  \n  \u002F\u002F Validate input first\n  if (!userId || !\u002F^\\d+$\u002F.test(userId)) {\n    return res.status(400).json({ \n      error: 'Invalid user ID' \n    });\n  }\n  \n  \u002F\u002F Use parameterized query\n  const user = await db.query(\n    'SELECT id, email, name FROM users WHERE id = $1',\n    [userId]\n  );\n  \n  if (!user) {\n    return res.status(404).json({ \n      error: 'User not found' \n    });\n  }\n  \n  res.json(user);\n});\n\\`\\`\\`\n\n#### 2. Use ORM with Proper Escaping\n\n\\`\\`\\`javascript\n\u002F\u002F ✅ Safe: Using Prisma ORM\napp.get('\u002Fapi\u002Fusers\u002F:id', async (req, res) => {\n  const userId = parseInt(req.params.id);\n  \n  if (isNaN(userId)) {\n    return res.status(400).json({ \n      error: 'Invalid user ID' \n    });\n  }\n  \n  const user = await prisma.user.findUnique({\n    where: { id: userId },\n    select: {\n      id: true,\n      email: true,\n      name: true,\n      \u002F\u002F Don't select sensitive fields\n    }\n  });\n  \n  if (!user) {\n    return res.status(404).json({ \n      error: 'User not found' \n    });\n  }\n  \n  res.json(user);\n});\n\\`\\`\\`\n\n#### 3. Implement Request Validation with Zod\n\n\\`\\`\\`javascript\nconst { z } = require('zod');\n\n\u002F\u002F Define validation schema\nconst createUserSchema = z.object({\n  email: z.string().email('Invalid email format'),\n  password: z.string()\n    .min(8, 'Password must be at least 8 characters')\n    .regex(\u002F[A-Z]\u002F, 'Password must contain uppercase letter')\n    .regex(\u002F[a-z]\u002F, 'Password must contain lowercase letter')\n    .regex(\u002F[0-9]\u002F, 'Password must contain number'),\n  name: z.string()\n    .min(2, 'Name must be at least 2 characters')\n    .max(100, 'Name too long'),\n  age: z.number()\n    .int('Age must be an integer')\n    .min(18, 'Must be 18 or older')\n    .max(120, 'Invalid age')\n    .optional()\n});\n\n\u002F\u002F Validation middleware\nfunction validateRequest(schema) {\n  return (req, res, next) => {\n    try {\n      schema.parse(req.body);\n      next();\n    } catch (error) {\n      res.status(400).json({\n        error: 'Validation failed',\n        details: error.errors\n      });\n    }\n  };\n}\n\n\u002F\u002F Use validation\napp.post('\u002Fapi\u002Fusers', \n  validateRequest(createUserSchema),\n  async (req, res) => {\n    \u002F\u002F Input is validated at this point\n    const { email, password, name, age } = req.body;\n    \n    \u002F\u002F Hash password\n    const passwordHash = await bcrypt.hash(password, 10);\n    \n    \u002F\u002F Create user\n    const user = await prisma.user.create({\n      data: {\n        email,\n        passwordHash,\n        name,\n        age\n      }\n    });\n    \n    \u002F\u002F Don't return password hash\n    const { passwordHash: _, ...userWithoutPassword } = user;\n    res.status(201).json(userWithoutPassword);\n  }\n);\n\\`\\`\\`\n\n#### 4. Sanitize Output to Prevent XSS\n\n\\`\\`\\`javascript\nconst DOMPurify = require('isomorphic-dompurify');\n\napp.post('\u002Fapi\u002Fcomments', authenticateToken, async (req, res) => {\n  const { content } = req.body;\n  \n  \u002F\u002F Validate\n  if (!content || content.length > 1000) {\n    return res.status(400).json({ \n      error: 'Invalid comment content' \n    });\n  }\n  \n  \u002F\u002F Sanitize HTML to prevent XSS\n  const sanitizedContent = DOMPurify.sanitize(content, {\n    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],\n    ALLOWED_ATTR: ['href']\n  });\n  \n  const comment = await prisma.comment.create({\n    data: {\n      content: sanitizedContent,\n      userId: req.user.userId\n    }\n  });\n  \n  res.status(201).json(comment);\n});\n\\`\\`\\`\n\n### Validation Checklist\n\n- [ ] Validate all user inputs\n- [ ] Use parameterized queries or ORM\n- [ ] Validate data types (string, number, email, etc.)\n- [ ] Validate data ranges (min\u002Fmax length, value ranges)\n- [ ] Sanitize HTML content\n- [ ] Escape special characters\n- [ ] Validate file uploads (type, size, content)\n- [ ] Use allowlists, not blocklists\n```\n\n\n### Example 3: Rate Limiting and DDoS Protection\n\n```markdown\n## Implementing Rate Limiting\n\n### Why Rate Limiting?\n\n- Prevent brute force attacks\n- Protect against DDoS\n- Prevent API abuse\n- Ensure fair usage\n- Reduce server costs\n\n### Implementation with Express Rate Limit\n\n\\`\\`\\`javascript\nconst rateLimit = require('express-rate-limit');\nconst RedisStore = require('rate-limit-redis');\nconst Redis = require('ioredis');\n\n\u002F\u002F Create Redis client\nconst redis = new Redis({\n  host: process.env.REDIS_HOST,\n  port: process.env.REDIS_PORT\n});\n\n\u002F\u002F General API rate limit\nconst apiLimiter = rateLimit({\n  store: new RedisStore({\n    client: redis,\n    prefix: 'rl:api:'\n  }),\n  windowMs: 15 * 60 * 1000, \u002F\u002F 15 minutes\n  max: 100, \u002F\u002F 100 requests per window\n  message: {\n    error: 'Too many requests, please try again later',\n    retryAfter: 900 \u002F\u002F seconds\n  },\n  standardHeaders: true, \u002F\u002F Return rate limit info in headers\n  legacyHeaders: false,\n  \u002F\u002F Custom key generator (by user ID or IP)\n  keyGenerator: (req) => {\n    return req.user?.userId || req.ip;\n  }\n});\n\n\u002F\u002F Strict rate limit for authentication endpoints\nconst authLimiter = rateLimit({\n  store: new RedisStore({\n    client: redis,\n    prefix: 'rl:auth:'\n  }),\n  windowMs: 15 * 60 * 1000, \u002F\u002F 15 minutes\n  max: 5, \u002F\u002F Only 5 login attempts per 15 minutes\n  skipSuccessfulRequests: true, \u002F\u002F Don't count successful logins\n  message: {\n    error: 'Too many login attempts, please try again later',\n    retryAfter: 900\n  }\n});\n\n\u002F\u002F Apply rate limiters\napp.use('\u002Fapi\u002F', apiLimiter);\napp.use('\u002Fapi\u002Fauth\u002Flogin', authLimiter);\napp.use('\u002Fapi\u002Fauth\u002Fregister', authLimiter);\n\n\u002F\u002F Custom rate limiter for expensive operations\nconst expensiveLimiter = rateLimit({\n  windowMs: 60 * 60 * 1000, \u002F\u002F 1 hour\n  max: 10, \u002F\u002F 10 requests per hour\n  message: {\n    error: 'Rate limit exceeded for this operation'\n  }\n});\n\napp.post('\u002Fapi\u002Freports\u002Fgenerate', \n  authenticateToken,\n  expensiveLimiter,\n  async (req, res) => {\n    \u002F\u002F Expensive operation\n  }\n);\n\\`\\`\\`\n\n### Advanced: Per-User Rate Limiting\n\n\\`\\`\\`javascript\n\u002F\u002F Different limits based on user tier\nfunction createTieredRateLimiter() {\n  const limits = {\n    free: { windowMs: 60 * 60 * 1000, max: 100 },\n    pro: { windowMs: 60 * 60 * 1000, max: 1000 },\n    enterprise: { windowMs: 60 * 60 * 1000, max: 10000 }\n  };\n  \n  return async (req, res, next) => {\n    const user = req.user;\n    const tier = user?.tier || 'free';\n    const limit = limits[tier];\n    \n    const key = \\`rl:user:\\${user.userId}\\`;\n    const current = await redis.incr(key);\n    \n    if (current === 1) {\n      await redis.expire(key, limit.windowMs \u002F 1000);\n    }\n    \n    if (current > limit.max) {\n      return res.status(429).json({\n        error: 'Rate limit exceeded',\n        limit: limit.max,\n        remaining: 0,\n        reset: await redis.ttl(key)\n      });\n    }\n    \n    \u002F\u002F Set rate limit headers\n    res.set({\n      'X-RateLimit-Limit': limit.max,\n      'X-RateLimit-Remaining': limit.max - current,\n      'X-RateLimit-Reset': await redis.ttl(key)\n    });\n    \n    next();\n  };\n}\n\napp.use('\u002Fapi\u002F', authenticateToken, createTieredRateLimiter());\n\\`\\`\\`\n\n### DDoS Protection with Helmet\n\n\\`\\`\\`javascript\nconst helmet = require('helmet');\n\napp.use(helmet({\n  \u002F\u002F Content Security Policy\n  contentSecurityPolicy: {\n    directives: {\n      defaultSrc: [\"'self'\"],\n      styleSrc: [\"'self'\", \"'unsafe-inline'\"],\n      scriptSrc: [\"'self'\"],\n      imgSrc: [\"'self'\", 'data:', 'https:']\n    }\n  },\n  \u002F\u002F Prevent clickjacking\n  frameguard: { action: 'deny' },\n  \u002F\u002F Hide X-Powered-By header\n  hidePoweredBy: true,\n  \u002F\u002F Prevent MIME type sniffing\n  noSniff: true,\n  \u002F\u002F Enable HSTS\n  hsts: {\n    maxAge: 31536000,\n    includeSubDomains: true,\n    preload: true\n  }\n}));\n\\`\\`\\`\n\n### Rate Limit Response Headers\n\n\\`\\`\\`\nX-RateLimit-Limit: 100\nX-RateLimit-Remaining: 87\nX-RateLimit-Reset: 1640000000\nRetry-After: 900\n\\`\\`\\`\n```\n\n## Best Practices\n\n### ✅ Do This\n\n- **Use HTTPS Everywhere** - Never send sensitive data over HTTP\n- **Implement Authentication** - Require authentication for protected endpoints\n- **Validate All Inputs** - Never trust user input\n- **Use Parameterized Queries** - Prevent SQL injection\n- **Implement Rate Limiting** - Protect against brute force and DDoS\n- **Hash Passwords** - Use bcrypt with salt rounds >= 10\n- **Use Short-Lived Tokens** - JWT access tokens should expire quickly\n- **Implement CORS Properly** - Only allow trusted origins\n- **Log Security Events** - Monitor for suspicious activity\n- **Keep Dependencies Updated** - Regularly update packages\n- **Use Security Headers** - Implement Helmet.js\n- **Sanitize Error Messages** - Don't leak sensitive information\n\n### ❌ Don't Do This\n\n- **Don't Store Passwords in Plain Text** - Always hash passwords\n- **Don't Use Weak Secrets** - Use strong, random JWT secrets\n- **Don't Trust User Input** - Always validate and sanitize\n- **Don't Expose Stack Traces** - Hide error details in production\n- **Don't Use String Concatenation for SQL** - Use parameterized queries\n- **Don't Store Sensitive Data in JWT** - JWTs are not encrypted\n- **Don't Ignore Security Updates** - Update dependencies regularly\n- **Don't Use Default Credentials** - Change all default passwords\n- **Don't Disable CORS Completely** - Configure it properly instead\n- **Don't Log Sensitive Data** - Sanitize logs\n\n## Common Pitfalls\n\n### Problem: JWT Secret Exposed in Code\n**Symptoms:** JWT secret hardcoded or committed to Git\n**Solution:**\n\\`\\`\\`javascript\n\u002F\u002F ❌ Bad\nconst JWT_SECRET = 'my-secret-key';\n\n\u002F\u002F ✅ Good\nconst JWT_SECRET = process.env.JWT_SECRET;\nif (!JWT_SECRET) {\n  throw new Error('JWT_SECRET environment variable is required');\n}\n\n\u002F\u002F Generate strong secret\n\u002F\u002F node -e \"console.log(require('crypto').randomBytes(64).toString('hex'))\"\n\\`\\`\\`\n\n### Problem: Weak Password Requirements\n**Symptoms:** Users can set weak passwords like \"password123\"\n**Solution:**\n\\`\\`\\`javascript\nconst passwordSchema = z.string()\n  .min(12, 'Password must be at least 12 characters')\n  .regex(\u002F[A-Z]\u002F, 'Must contain uppercase letter')\n  .regex(\u002F[a-z]\u002F, 'Must contain lowercase letter')\n  .regex(\u002F[0-9]\u002F, 'Must contain number')\n  .regex(\u002F[^A-Za-z0-9]\u002F, 'Must contain special character');\n\n\u002F\u002F Or use a password strength library\nconst zxcvbn = require('zxcvbn');\nconst result = zxcvbn(password);\nif (result.score \u003C 3) {\n  return res.status(400).json({\n    error: 'Password too weak',\n    suggestions: result.feedback.suggestions\n  });\n}\n\\`\\`\\`\n\n### Problem: Missing Authorization Checks\n**Symptoms:** Users can access resources they shouldn't\n**Solution:**\n\\`\\`\\`javascript\n\u002F\u002F ❌ Bad: Only checks authentication\napp.delete('\u002Fapi\u002Fposts\u002F:id', authenticateToken, async (req, res) => {\n  await prisma.post.delete({ where: { id: req.params.id } });\n  res.json({ success: true });\n});\n\n\u002F\u002F ✅ Good: Checks both authentication and authorization\napp.delete('\u002Fapi\u002Fposts\u002F:id', authenticateToken, async (req, res) => {\n  const post = await prisma.post.findUnique({\n    where: { id: req.params.id }\n  });\n  \n  if (!post) {\n    return res.status(404).json({ error: 'Post not found' });\n  }\n  \n  \u002F\u002F Check if user owns the post or is admin\n  if (post.userId !== req.user.userId && req.user.role !== 'admin') {\n    return res.status(403).json({ \n      error: 'Not authorized to delete this post' \n    });\n  }\n  \n  await prisma.post.delete({ where: { id: req.params.id } });\n  res.json({ success: true });\n});\n\\`\\`\\`\n\n### Problem: Verbose Error Messages\n**Symptoms:** Error messages reveal system details\n**Solution:**\n\\`\\`\\`javascript\n\u002F\u002F ❌ Bad: Exposes database details\napp.post('\u002Fapi\u002Fusers', async (req, res) => {\n  try {\n    const user = await prisma.user.create({ data: req.body });\n    res.json(user);\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n    \u002F\u002F Error: \"Unique constraint failed on the fields: (`email`)\"\n  }\n});\n\n\u002F\u002F ✅ Good: Generic error message\napp.post('\u002Fapi\u002Fusers', async (req, res) => {\n  try {\n    const user = await prisma.user.create({ data: req.body });\n    res.json(user);\n  } catch (error) {\n    console.error('User creation error:', error); \u002F\u002F Log full error\n    \n    if (error.code === 'P2002') {\n      return res.status(400).json({ \n        error: 'Email already exists' \n      });\n    }\n    \n    res.status(500).json({ \n      error: 'An error occurred while creating user' \n    });\n  }\n});\n\\`\\`\\`\n\n## Security Checklist\n\n### Authentication & Authorization\n- [ ] Implement strong authentication (JWT, OAuth 2.0)\n- [ ] Use HTTPS for all endpoints\n- [ ] Hash passwords with bcrypt (salt rounds >= 10)\n- [ ] Implement token expiration\n- [ ] Add refresh token mechanism\n- [ ] Verify user authorization for each request\n- [ ] Implement role-based access control (RBAC)\n\n### Input Validation\n- [ ] Validate all user inputs\n- [ ] Use parameterized queries or ORM\n- [ ] Sanitize HTML content\n- [ ] Validate file uploads\n- [ ] Implement request schema validation\n- [ ] Use allowlists, not blocklists\n\n### Rate Limiting & DDoS Protection\n- [ ] Implement rate limiting per user\u002FIP\n- [ ] Add stricter limits for auth endpoints\n- [ ] Use Redis for distributed rate limiting\n- [ ] Return proper rate limit headers\n- [ ] Implement request throttling\n\n### Data Protection\n- [ ] Use HTTPS\u002FTLS for all traffic\n- [ ] Encrypt sensitive data at rest\n- [ ] Don't store sensitive data in JWT\n- [ ] Sanitize error messages\n- [ ] Implement proper CORS configuration\n- [ ] Use security headers (Helmet.js)\n\n### Monitoring & Logging\n- [ ] Log security events\n- [ ] Monitor for suspicious activity\n- [ ] Set up alerts for failed auth attempts\n- [ ] Track API usage patterns\n- [ ] Don't log sensitive data\n\n## OWASP API Security Top 10\n\n1. **Broken Object Level Authorization** - Always verify user can access resource\n2. **Broken Authentication** - Implement strong authentication mechanisms\n3. **Broken Object Property Level Authorization** - Validate which properties user can access\n4. **Unrestricted Resource Consumption** - Implement rate limiting and quotas\n5. **Broken Function Level Authorization** - Verify user role for each function\n6. **Unrestricted Access to Sensitive Business Flows** - Protect critical workflows\n7. **Server Side Request Forgery (SSRF)** - Validate and sanitize URLs\n8. **Security Misconfiguration** - Use security best practices and headers\n9. **Improper Inventory Management** - Document and secure all API endpoints\n10. **Unsafe Consumption of APIs** - Validate data from third-party APIs\n\n## Related Skills\n\n- `@ethical-hacking-methodology` - Security testing perspective\n- `@sql-injection-testing` - Testing for SQL injection\n- `@xss-html-injection` - Testing for XSS vulnerabilities\n- `@broken-authentication` - Authentication vulnerabilities\n- `@backend-dev-guidelines` - Backend development standards\n- `@systematic-debugging` - Debug security issues\n\n## Additional Resources\n\n- [OWASP API Security Top 10](https:\u002F\u002Fowasp.org\u002Fwww-project-api-security\u002F)\n- [JWT Best Practices](https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc8725)\n- [Express Security Best Practices](https:\u002F\u002Fexpressjs.com\u002Fen\u002Fadvanced\u002Fbest-practice-security.html)\n- [Node.js Security Checklist](https:\u002F\u002Fblog.risingstack.com\u002Fnode-js-security-checklist\u002F)\n- [API Security Checklist](https:\u002F\u002Fgithub.com\u002Fshieldfy\u002FAPI-Security-Checklist)\n\n---\n\n**Pro Tip:** Security is not a one-time task - regularly audit your APIs, keep dependencies updated, and stay informed about new vulnerabilities!\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,180,185,"2026-05-16 13:03:28",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":25,"skillCount":32,"createdAt":26},"后端开发","backend","mdi-server","API、数据库、服务端架构",296,[34],{"id":35,"skillId":4,"version":36,"fileName":37,"fileSize":38,"filePath":39,"fileHash":40,"manifest":41,"createdAt":19},"b2eaa1d8-ac13-44ec-8145-b79d68899355","1.0.0","api-security-best-practices.zip",7520,"uploads\u002Fskills\u002F5375a30e-5086-41bb-808a-4aec34d67fbf\u002Fapi-security-best-practices.zip","e8933aa913550c767cc5a30a272e4f0b5b8368b725a36bf9a4ffe0ccff70f2bd","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":23777}]",{"code":43,"message":44,"data":45},200,"success",{"items":46,"stats":47,"page":50},[],{"averageRating":48,"totalRatings":48,"ratingCounts":49},0,[48,48,48,48,48],{"limit":51,"offset":48,"hasMore":52,"nextOffset":51,"ratedOnly":16},15,false]