Token导航 LogoToken导航

Agent Skill · 研究检索

security-practices(安全实践)

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

security-practices 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证为 MIT,第三方扫描已通过,按安装量在研究检索类的 73,674 个 Skill 里排第 47,881。

总安装 713周安装 30GitHub Stars 12下载 250核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:security-practices(安全实践)
来源仓库:https://github.com/miles990/claude-software-skills
仓库路径:skills/security-practices
安装命令:
npx skills add https://github.com/miles990/claude-software-skills --skill security-practices
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/miles990/claude-software-skills --skill security-practices

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于辅助安全审计、权限检查和凭据风险排查。适合梳理敏感配置、分析鉴权逻辑或生成复核清单。使用时不能将工具输出直接当作最终结论。适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。涉及密钥或用户数据时应确认最小权限和操作边界。

security-practices 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/security-practices

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/miles990/claude-software-skills --skill securi…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

security-practices 怎么安装?

在终端执行 npx skills add https://github.com/miles990/claude-software-skills --skill security-practic…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

security-practices 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

security-practices 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

security-practices 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

security-practices 用的人多吗?

公开数据是累计安装 713 次,近一周安装 30 次,下载 250 次,GitHub 12 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

security-practices 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
security-practices

安全实践 · 本页

71312接触敏感数据MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Security Practices

Overview

Essential security practices for application development. Covers OWASP Top 10 and secure coding guidelines.


OWASP Top 10

1. Injection (SQL, NoSQL, Command)

// ❌ SQL Injection vulnerable
const query = `SELECT * FROM users WHERE email = '${email}'`;
// Attack: email = "'; DROP TABLE users; --"

// ✅ Parameterized query
const result = await db.query(
  'SELECT * FROM users WHERE email = $1',
  [email]
);

// ✅ ORM with parameterization
const user = await prisma.user.findUnique({
  where: { email }
});

// ❌ Command injection vulnerable
exec(`ping ${userInput}`);
// Attack: userInput = "google.com; rm -rf /"

// ✅ Use arrays, not string concatenation
execFile('ping', ['-c', '4', hostname]);

2. Broken Authentication

// Strong password requirements
const passwordSchema = z.string()
  .min(12)
  .regex(/[A-Z]/, 'Must contain uppercase')
  .regex(/[a-z]/, 'Must contain lowercase')
  .regex(/[0-9]/, 'Must contain number')
  .regex(/[^A-Za-z0-9]/, 'Must contain special character');

// Secure password hashing
import argon2 from 'argon2';

async function hashPassword(password: string): Promise<string> {
  return argon2.hash(password, {
    type: argon2.argon2id,
    memoryCost: 65536,  // 64 MB
    timeCost: 3,
    parallelism: 4
  });
}

async function verifyPassword(hash: string, password: string): Promise<boolean> {
  return argon2.verify(hash, password);
}

// Rate limiting login attempts
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts
  message: 'Too many login attempts'
});

app.post('/login', loginLimiter, handleLogin);

3. Cross-Site Scripting (XSS)

// ❌ Direct HTML insertion
element.innerHTML = userInput;
// Attack: userInput = "<script>stealCookies()</script>"

// ✅ Use textContent for text
element.textContent = userInput;

// ✅ React auto-escapes by default
function UserName({ name }: { name: string }) {
  return <span>{name}</span>; // Safe
}

// ⚠️ dangerouslySetInnerHTML requires sanitization
import DOMPurify from 'dompurify';

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

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

// Content Security Policy header
app.use((req, res, next) => {
  res.setHeader('Content-Security-Policy',
    "default-src 'self'; " +
    "script-src 'self' 'unsafe-inline'; " +
    "style-src 'self' 'unsafe-inline'; " +
    "img-src 'self' data: https:;"
  );
  next();
});

4. Insecure Direct Object References

// ❌ No authorization check
app.get('/api/documents/:id', async (req, res) => {
  const doc = await db.documents.findById(req.params.id);
  res.json(doc);
});
// Attack: User can access any document by guessing ID

// ✅ Verify ownership
app.get('/api/documents/:id', auth, async (req, res) => {
  const doc = await db.documents.findById(req.params.id);

  if (!doc) {
    return res.status(404).json({ error: 'Not found' });
  }

  if (doc.ownerId !== req.user.id && !req.user.isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }

  res.json(doc);
});

// ✅ Use UUIDs instead of sequential IDs
// Harder to guess, but still check authorization!
const docId = crypto.randomUUID();

5. Cross-Site Request Forgery (CSRF)

// CSRF token middleware
import csrf from 'csurf';

const csrfProtection = csrf({ cookie: true });

app.get('/form', csrfProtection, (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/submit', csrfProtection, (req, res) => {
  // Token automatically validated
  // ...
});

// In form
<form action="/submit" method="POST">
  <input type="hidden" name="_csrf" value="{{csrfToken}}" />
  <!-- form fields -->
</form>

// SameSite cookies
res.cookie('sessionId', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict' // or 'lax'
});

Authentication

JWT Best Practices

import jwt from 'jsonwebtoken';

// Access token (short-lived)
function generateAccessToken(user: User): string {
  return jwt.sign(
    { sub: user.id, role: user.role },
    process.env.JWT_SECRET!,
    { expiresIn: '15m' }
  );
}

// Refresh token (long-lived, stored securely)
function generateRefreshToken(user: User): string {
  const token = jwt.sign(
    { sub: user.id, type: 'refresh' },
    process.env.JWT_REFRESH_SECRET!,
    { expiresIn: '7d' }
  );

  // Store in database to allow revocation
  db.refreshTokens.create({
    userId: user.id,
    token: hashToken(token),
    expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
  });

  return token;
}

// Verify and refresh
async function refreshAccessToken(refreshToken: string) {
  const payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!);

  // Check if token is revoked
  const storedToken = await db.refreshTokens.findOne({
    userId: payload.sub,
    token: hashToken(refreshToken)
  });

  if (!storedToken) {
    throw new Error('Token revoked');
  }

  const user = await db.users.findById(payload.sub);
  return generateAccessToken(user);
}

OAuth 2.0 / OIDC

import { OAuth2Client } from 'google-auth-library';

const client = new OAuth2Client(
  process.env.GOOGLE_CLIENT_ID,
  process.env.GOOGLE_CLIENT_SECRET,
  'https://myapp.com/auth/google/callback'
);

// Generate auth URL
app.get('/auth/google', (req, res) => {
  const url = client.generateAuthUrl({
    scope: ['openid', 'email', 'profile'],
    state: generateState(req.session.id) // CSRF protection
  });
  res.redirect(url);
});

// Handle callback
app.get('/auth/google/callback', async (req, res) => {
  const { code, state } = req.query;

  // Verify state
  if (!verifyState(state, req.session.id)) {
    return res.status(400).send('Invalid state');
  }

  // Exchange code for tokens
  const { tokens } = await client.getToken(code);

  // Verify ID token
  const ticket = await client.verifyIdToken({
    idToken: tokens.id_token,
    audience: process.env.GOOGLE_CLIENT_ID
  });

  const payload = ticket.getPayload();

  // Create or update user
  const user = await upsertUser({
    email: payload.email,
    name: payload.name,
    picture: payload.picture
  });

  // Create session
  req.session.userId = user.id;
  res.redirect('/dashboard');
});

Authorization

Role-Based Access Control (RBAC)

// Define permissions
const PERMISSIONS = {
  admin: ['read', 'write', 'delete', 'admin'],
  editor: ['read', 'write'],
  viewer: ['read']
} as const;

// Middleware
function requirePermission(permission: string) {
  return (req: Request, res: Response, next: NextFunction) => {
    const userPermissions = PERMISSIONS[req.user.role] || [];

    if (!userPermissions.includes(permission)) {
      return res.status(403).json({ error: 'Forbidden' });
    }

    next();
  };
}

// Usage
app.delete('/api/posts/:id', auth, requirePermission('delete'), deletePost);

Attribute-Based Access Control (ABAC)

interface Policy {
  effect: 'allow' | 'deny';
  resource: string;
  action: string;
  condition?: (context: Context) => boolean;
}

const policies: Policy[] = [
  {
    effect: 'allow',
    resource: 'document',
    action: 'read',
    condition: (ctx) => ctx.resource.isPublic || ctx.user.id === ctx.resource.ownerId
  },
  {
    effect: 'allow',
    resource: 'document',
    action: 'write',
    condition: (ctx) => ctx.user.id === ctx.resource.ownerId
  },
  {
    effect: 'allow',
    resource: '*',
    action: '*',
    condition: (ctx) => ctx.user.role === 'admin'
  }
];

function isAllowed(user: User, action: string, resource: Resource): boolean {
  const context = { user, resource };

  for (const policy of policies) {
    if (
      (policy.resource === '*' || policy.resource === resource.type) &&
      (policy.action === '*' || policy.action === action)
    ) {
      if (!policy.condition || policy.condition(context)) {
        return policy.effect === 'allow';
      }
    }
  }

  return false; // Deny by default
}

Secrets Management

// ❌ Never hardcode secrets
const apiKey = 'sk_live_1234567890';

// ✅ Use environment variables
const apiKey = process.env.API_KEY;

// ✅ Use secret managers
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';

const client = new SecretManagerServiceClient();

async function getSecret(name: string): Promise<string> {
  const [version] = await client.accessSecretVersion({
    name: `projects/my-project/secrets/${name}/versions/latest`
  });

  return version.payload.data.toString();
}

// ✅ Rotate secrets regularly
// Store secret versions, not raw secrets
// Use short-lived tokens where possible

Input Validation

import { z } from 'zod';

// Define strict schemas
const createUserSchema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100).regex(/^[\w\s-]+$/),
  age: z.number().int().min(0).max(150).optional()
});

// Validate at boundaries
app.post('/api/users', async (req, res) => {
  const result = createUserSchema.safeParse(req.body);

  if (!result.success) {
    return res.status(400).json({
      error: 'Validation failed',
      details: result.error.flatten()
    });
  }

  // result.data is typed and validated
  const user = await createUser(result.data);
  res.json(user);
});

// File upload validation
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];

function validateFile(file: Express.Multer.File) {
  if (file.size > MAX_FILE_SIZE) {
    throw new Error('File too large');
  }

  if (!ALLOWED_TYPES.includes(file.mimetype)) {
    throw new Error('Invalid file type');
  }

  // Also check magic bytes, not just extension
  const fileType = await fileTypeFromBuffer(file.buffer);
  if (!fileType || !ALLOWED_TYPES.includes(fileType.mime)) {
    throw new Error('Invalid file content');
  }
}

Security Headers

import helmet from 'helmet';

app.use(helmet());

// Or configure individually
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "'unsafe-inline'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "data:", "https:"],
    connectSrc: ["'self'", "https://api.example.com"],
    fontSrc: ["'self'"],
    objectSrc: ["'none'"],
    frameAncestors: ["'none'"]
  }
}));

app.use(helmet.hsts({
  maxAge: 31536000,
  includeSubDomains: true,
  preload: true
}));

Related Skills

  • [[authentication]] - Auth patterns
  • [[api-design]] - API security
  • [[devops-cicd]] - Security in pipelines

平台分布

Antigravity

27.85%
按下载量换算70

Gemini CLI

23.34%
按下载量换算58

windsurf

15.89%
按下载量换算40

Claude Code

11.47%
按下载量换算29

Codex

7.33%
按下载量换算18

OpenCode

3.33%
按下载量换算8

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills