用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/miles990/claude-software-skills --skill security-practices命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | security-practices |
| description | OWASP Top 10, authentication, and secure coding practices |
| domain | software-engineering |
| version | 1.0.0 |
| tags | ["security","owasp","authentication","authorization","encryption","xss","csrf"] |
| triggers | {"keywords":{"primary":["security","owasp","authentication","authorization","encryption","vulnerability"],"secondary":["xss","csrf","sql injection","jwt","oauth","cors","sanitize","validate"]},"context_boost":["secure","protect","attack","hack"],"context_penalty":["design","ui","ux"],"priority":"high"} |
Essential security practices for application development. Covers OWASP Top 10 and secure coding guidelines.
// ❌ 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]);
// 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);
}
loginLimiter = ({
: * * ,
: ,
:
});
app.(, loginLimiter, handleLogin);
// ❌ 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',
+
+
+
);
();
});
// ❌ 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();
// 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'
});
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 * * )
});
token;
}
() {
payload = jwt.(refreshToken, process..!);
storedToken = db..({
: payload.,
: (refreshToken)
});
(!storedToken) {
();
}
user = db..(payload.);
(user);
}
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);
ticket = client.({
: tokens.,
: process..
});
payload = ticket.();
user = ({
: payload.,
: payload.,
: payload.
});
req.. = user.;
res.();
});
// 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);
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. ===
}
];
(): {
context = { user, resource };
( policy policies) {
(
(policy. === || policy. === resource.) &&
(policy. === || policy. === action)
) {
(!policy. || policy.(context)) {
policy. === ;
}
}
}
;
}
// ❌ 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
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. > ) {
();
}
(!.(file.)) {
();
}
fileType = (file.);
(!fileType || !.(fileType.)) {
();
}
}
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
}));