pitfalls-security
Security patterns for session keys, caching, logging, and environment variables. Use when implementing authentication, caching sensitive data, or setting up logging. Triggers on: session key, private key, cache, logging, secrets, environment variable.
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o pitfalls-security.zip https://jpskill.com/download/17448.zip && unzip -o pitfalls-security.zip && rm pitfalls-security.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/17448.zip -OutFile "$d\pitfalls-security.zip"; Expand-Archive "$d\pitfalls-security.zip" -DestinationPath $d -Force; ri "$d\pitfalls-security.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
pitfalls-security.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
pitfalls-securityフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
セキュリティの落とし穴
セキュリティに関するよくある落とし穴と正しいパターンについて説明します。
どのような時に使うか
- セッションキー管理の実装
- データのキャッシュ(特に機密性の高いデータ)
- 構造化ロギングの設定
- 環境変数の取り扱い
- セキュリティ上重要なコードのレビュー
ワークフロー
ステップ 1: キーのストレージの確認
プレーンテキストで秘密鍵が保存されていないことを確認します。
ステップ 2: キャッシュの安全性の確認
機密データが不適切にキャッシュされていないことを確認します。
ステップ 3: ロギングの確認
ログにシークレットが含まれていないことを確認します。
セッションキーのセキュリティ
// ❌ 秘密鍵を絶対に保存しないでください
localStorage.setItem('privateKey', key); // 壊滅的
// ✅ 制限された権限を持つセッションキーを使用する
interface SessionKey {
address: Address;
permissions: Permission[];
expiresAt: Date;
maxPerTrade: bigint;
}
// ✅ 保存されたクレデンシャルには AES-256-GCM を使用する
import { createCipheriv, randomBytes } from 'crypto';
const iv = randomBytes(16);
const cipher = createCipheriv('aes-256-gcm', key, iv);
// ✅ すべてのキー操作の監査ログ
await auditLog.create({
action: 'SESSION_KEY_CREATED',
userId,
metadata: { permissions, expiresAt },
});
環境変数
// Frontend (Vite)
const apiUrl = import.meta.env.VITE_API_URL; // ✅ VITE_ プレフィックスが必要
// ❌ process.env.API_URL はフロントエンドでは動作しません
// Backend
const dbUrl = process.env.DATABASE_URL;
// ❌ シークレットを絶対にログに記録しないでください
console.log('Config:', config); // シークレットが含まれている可能性があります!
// ✅ 安全にログを記録する
console.log('Config loaded for:', config.environment);
キャッシュ戦略
// ✅ コストのかかる計算のためのサーバーサイドキャッシュ
const priceCache = new Map<string, { value: number; expires: number }>();
function getCachedPrice(token: string): number | null {
const cached = priceCache.get(token);
if (cached && cached.expires > Date.now()) {
return cached.value;
}
return null;
}
// ✅ データの鮮度ニーズに基づいた TTL
const CACHE_TTL = {
tokenPrice: 10_000, // 10s - 価格はすぐに変わる
poolReserves: 5_000, // 5s - スワップに不可欠
gasPrice: 15_000, // 15s
userBalance: 30_000, // 30s
tokenMetadata: 3600_000, // 1 時間 - めったに変わらない
};
// ❌ ユーザー固有の機密データをキャッシュしないでください
cache.set(`user:${userId}:privateKey`, key); // 絶対にしないでください!
構造化ロギング
// ✅ 構造化ロギング (JSON 形式)
const logger = {
info: (message: string, context?: object) => {
console.log(JSON.stringify({
level: 'info',
message,
timestamp: new Date().toISOString(),
...context,
}));
},
error: (message: string, error: Error, context?: object) => {
console.error(JSON.stringify({
level: 'error',
message,
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
...context,
}));
},
};
// ✅ コンテキストを含める
logger.info('Trade executed', {
userId: 'user123',
txHash: '0x...',
chain: 'ethereum',
profit: '12.34',
});
// ❌ シークレットを絶対にログに記録しないでください
logger.info('Config', { apiKey: process.env.API_KEY }); // 絶対にしないでください!
監査ロギング
// ✅ 重要な操作の監査ログ
await auditLog.create({
action: 'TRADE_EXECUTED',
userId,
before: previousState,
after: newState,
timestamp: new Date(),
metadata: { txHash, chain },
});
簡単なチェックリスト
- [ ] localStorage に秘密鍵がないこと
- [ ] セッションキーに有効期限と制限があること
- [ ] 保存されたクレデンシャルに AES-256-GCM を使用していること
- [ ] 重要な操作の監査ログ
- [ ] console.log にシークレットがないこと
- [ ] 機密データが不適切にキャッシュされていないこと
- [ ] フロントエンドの環境変数に VITE_ プレフィックスが付いていること
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Security Pitfalls
Common pitfalls and correct patterns for security.
When to Use
- Implementing session key management
- Caching data (especially sensitive)
- Setting up structured logging
- Handling environment variables
- Reviewing security-sensitive code
Workflow
Step 1: Check Key Storage
Verify no private keys stored in plaintext.
Step 2: Verify Cache Safety
Ensure sensitive data not cached inappropriately.
Step 3: Check Logging
Confirm no secrets in logs.
Session Key Security
// ❌ NEVER store private keys
localStorage.setItem('privateKey', key); // CATASTROPHIC
// ✅ Use session keys with limited permissions
interface SessionKey {
address: Address;
permissions: Permission[];
expiresAt: Date;
maxPerTrade: bigint;
}
// ✅ AES-256-GCM for any stored credentials
import { createCipheriv, randomBytes } from 'crypto';
const iv = randomBytes(16);
const cipher = createCipheriv('aes-256-gcm', key, iv);
// ✅ Audit logging for all key operations
await auditLog.create({
action: 'SESSION_KEY_CREATED',
userId,
metadata: { permissions, expiresAt },
});
Environment Variables
// Frontend (Vite)
const apiUrl = import.meta.env.VITE_API_URL; // ✅ VITE_ prefix required
// ❌ process.env.API_URL won't work in frontend
// Backend
const dbUrl = process.env.DATABASE_URL;
// ❌ NEVER log secrets
console.log('Config:', config); // May contain secrets!
// ✅ Log safely
console.log('Config loaded for:', config.environment);
Caching Strategies
// ✅ Server-side cache for expensive computations
const priceCache = new Map<string, { value: number; expires: number }>();
function getCachedPrice(token: string): number | null {
const cached = priceCache.get(token);
if (cached && cached.expires > Date.now()) {
return cached.value;
}
return null;
}
// ✅ TTL based on data freshness needs
const CACHE_TTL = {
tokenPrice: 10_000, // 10s - prices change fast
poolReserves: 5_000, // 5s - critical for swaps
gasPrice: 15_000, // 15s
userBalance: 30_000, // 30s
tokenMetadata: 3600_000, // 1 hour - rarely changes
};
// ❌ Never cache user-specific sensitive data
cache.set(`user:${userId}:privateKey`, key); // NEVER!
Structured Logging
// ✅ Structured logging (JSON format)
const logger = {
info: (message: string, context?: object) => {
console.log(JSON.stringify({
level: 'info',
message,
timestamp: new Date().toISOString(),
...context,
}));
},
error: (message: string, error: Error, context?: object) => {
console.error(JSON.stringify({
level: 'error',
message,
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
...context,
}));
},
};
// ✅ Include context
logger.info('Trade executed', {
userId: 'user123',
txHash: '0x...',
chain: 'ethereum',
profit: '12.34',
});
// ❌ NEVER log secrets
logger.info('Config', { apiKey: process.env.API_KEY }); // NEVER!
Audit Logging
// ✅ Audit logging for sensitive operations
await auditLog.create({
action: 'TRADE_EXECUTED',
userId,
before: previousState,
after: newState,
timestamp: new Date(),
metadata: { txHash, chain },
});
Quick Checklist
- [ ] No private keys in localStorage
- [ ] Session keys have expiry and limits
- [ ] AES-256-GCM for stored credentials
- [ ] Audit logging for sensitive operations
- [ ] No secrets in console.log
- [ ] Sensitive data not cached inappropriately
- [ ] VITE_ prefix for frontend env vars