重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
security-checklist by jamditis/claude-skills-journalism
npx skills add https://github.com/jamditis/claude-skills-journalism --skill security-checklist在任何 Web 应用程序上线前的最低可行安全性。这并非详尽无遗——它是防止明显灾难的基线。
在任何生产部署之前,请运行此清单。如果某项无法勾选,请先修复它。
crypto.randomBytes 或等效方法)广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
*)// BAD: SQL injection
db.query(`SELECT * FROM users WHERE id = ${req.params.id}`);
// GOOD: Parameterized query
db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
// BAD: XSS vulnerability
res.send(`<h1>Hello ${req.query.name}</h1>`);
// GOOD: Use template engine with auto-escaping
res.render('greeting', { name: req.query.name });
// BAD: Secrets in code
const API_KEY = 'sk_live_abc123';
// GOOD: Environment variables
const API_KEY = process.env.API_KEY;
# BAD: SQL injection
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# GOOD: Parameterized query
cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])
# BAD: Pickle deserialization (RCE vulnerability)
data = pickle.loads(user_input)
# GOOD: Use JSON for untrusted data
data = json.loads(user_input)
# BAD: Debug mode in production
app.run(debug=True)
# GOOD: Debug off, proper error handling
app.run(debug=False)
// BAD: XSS via dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userContent }} />
// GOOD: Let React escape content
<div>{userContent}</div>
// BAD: Storing tokens in localStorage (XSS accessible)
localStorage.setItem('token', authToken);
// BETTER: HttpOnly cookies (not accessible via JS)
// Set via server response header
// BAD: Exposing API keys in frontend code
const API_KEY = 'sk_live_abc123';
// GOOD: Proxy through your backend
const response = await fetch('/api/proxy/external-service');
const bcrypt = require('bcrypt');
// Hashing (on registration)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
// Verification (on login)
const isValid = await bcrypt.compare(plainPassword, hashedPassword);
import bcrypt
# Hashing
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
# Verification
is_valid = bcrypt.checkpw(password.encode('utf-8'), hashed)
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=your-256-bit-secret-here
API_KEY=sk_test_xxxxx
.env
.env.local
.env.*.local
*.pem
*.key
credentials.json
secrets/
// Node.js with dotenv
require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;
// Fail fast if missing
if (!process.env.JWT_SECRET) {
throw new Error('JWT_SECRET environment variable is required');
}
-- Enable RLS on table
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
-- Users can only read their own documents
CREATE POLICY "Users can read own documents" ON documents
FOR SELECT USING (auth.uid() = user_id);
-- Users can only insert documents as themselves
CREATE POLICY "Users can insert own documents" ON documents
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Users can only update their own documents
CREATE POLICY "Users can update own documents" ON documents
FOR UPDATE USING (auth.uid() = user_id);
-- Users can only delete their own documents
CREATE POLICY "Users can delete own documents" ON documents
FOR DELETE USING (auth.uid() = user_id);
const cors = require('cors');
// BAD: Allow all origins
app.use(cors());
// GOOD: Specific origins
app.use(cors({
origin: ['https://myapp.com', 'https://www.myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
// Essential security headers
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Content-Security-Policy', "default-src 'self'");
// NEVER log these:
// - Passwords (plain or hashed)
// - Session tokens / JWTs
// - API keys
// - Credit card numbers
// - Social security numbers
// - Full request bodies with user data
// BAD
console.log('Login attempt:', { email, password });
console.log('Request:', req.body);
// GOOD
console.log('Login attempt:', { email, success: false, reason: 'invalid_password' });
console.log('Request:', { endpoint: req.path, method: req.method, userId: req.user?.id });
git filter-branch 或 BFG Repo-Cleaner 从历史记录中移除console.log、logger.、print(每周安装数
52
代码仓库
GitHub 星标数
84
首次出现
2026年1月21日
安全审计
安装于
gemini-cli48
codex48
opencode47
cursor45
amp43
github-copilot43
Minimum viable security before shipping any web application. This is not exhaustive—it's the baseline that prevents obvious disasters.
Run through this checklist before any production deployment. If you can't check an item, fix it first.
crypto.randomBytes or equivalent)* in production)// BAD: SQL injection
db.query(`SELECT * FROM users WHERE id = ${req.params.id}`);
// GOOD: Parameterized query
db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
// BAD: XSS vulnerability
res.send(`<h1>Hello ${req.query.name}</h1>`);
// GOOD: Use template engine with auto-escaping
res.render('greeting', { name: req.query.name });
// BAD: Secrets in code
const API_KEY = 'sk_live_abc123';
// GOOD: Environment variables
const API_KEY = process.env.API_KEY;
# BAD: SQL injection
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# GOOD: Parameterized query
cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])
# BAD: Pickle deserialization (RCE vulnerability)
data = pickle.loads(user_input)
# GOOD: Use JSON for untrusted data
data = json.loads(user_input)
# BAD: Debug mode in production
app.run(debug=True)
# GOOD: Debug off, proper error handling
app.run(debug=False)
// BAD: XSS via dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userContent }} />
// GOOD: Let React escape content
<div>{userContent}</div>
// BAD: Storing tokens in localStorage (XSS accessible)
localStorage.setItem('token', authToken);
// BETTER: HttpOnly cookies (not accessible via JS)
// Set via server response header
// BAD: Exposing API keys in frontend code
const API_KEY = 'sk_live_abc123';
// GOOD: Proxy through your backend
const response = await fetch('/api/proxy/external-service');
const bcrypt = require('bcrypt');
// Hashing (on registration)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);
// Verification (on login)
const isValid = await bcrypt.compare(plainPassword, hashedPassword);
import bcrypt
# Hashing
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))
# Verification
is_valid = bcrypt.checkpw(password.encode('utf-8'), hashed)
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=your-256-bit-secret-here
API_KEY=sk_test_xxxxx
.env
.env.local
.env.*.local
*.pem
*.key
credentials.json
secrets/
// Node.js with dotenv
require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;
// Fail fast if missing
if (!process.env.JWT_SECRET) {
throw new Error('JWT_SECRET environment variable is required');
}
-- Enable RLS on table
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
-- Users can only read their own documents
CREATE POLICY "Users can read own documents" ON documents
FOR SELECT USING (auth.uid() = user_id);
-- Users can only insert documents as themselves
CREATE POLICY "Users can insert own documents" ON documents
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Users can only update their own documents
CREATE POLICY "Users can update own documents" ON documents
FOR UPDATE USING (auth.uid() = user_id);
-- Users can only delete their own documents
CREATE POLICY "Users can delete own documents" ON documents
FOR DELETE USING (auth.uid() = user_id);
const cors = require('cors');
// BAD: Allow all origins
app.use(cors());
// GOOD: Specific origins
app.use(cors({
origin: ['https://myapp.com', 'https://www.myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
// Essential security headers
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Content-Security-Policy', "default-src 'self'");
// NEVER log these:
// - Passwords (plain or hashed)
// - Session tokens / JWTs
// - API keys
// - Credit card numbers
// - Social security numbers
// - Full request bodies with user data
// BAD
console.log('Login attempt:', { email, password });
console.log('Request:', req.body);
// GOOD
console.log('Login attempt:', { email, success: false, reason: 'invalid_password' });
console.log('Request:', { endpoint: req.path, method: req.method, userId: req.user?.id });
git filter-branch or BFG Repo-Cleaner to remove from historyconsole.log, logger., print(Weekly Installs
52
Repository
GitHub Stars
84
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli48
codex48
opencode47
cursor45
amp43
github-copilot43