aiwf
Version:
AI Workflow Framework for Claude Code with multi-language support (Korean/English)
498 lines (415 loc) • 12.4 kB
Markdown
```sql
-- 취약한 코드
SELECT * FROM users WHERE username = '$username' AND password = '$password';
-- 공격 예시
username: admin' OR '1'='1' --
password: anything
-- 방어 코드 (파라미터화된 쿼리)
const query = 'SELECT * FROM users WHERE username = ? AND password = ?';
db.query(query, [username, password]);
```
```javascript
// 저장형 XSS 방어
function sanitizeUserInput(input) {
// DOMPurify 라이브러리 사용
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href']
});
}
// 반사형 XSS 방어
function renderUserContent(content) {
const div = document.createElement('div');
div.textContent = content; // innerHTML 대신 textContent 사용
return div;
}
// CSP 헤더 설정
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}';
```
```javascript
// CSRF 토큰 생성
class CSRFProtection {
generateToken(sessionId) {
const token = crypto.randomBytes(32).toString('hex');
this.storeToken(sessionId, token);
return token;
}
validateToken(sessionId, token) {
const storedToken = this.getToken(sessionId);
if (!storedToken || storedToken !== token) {
throw new SecurityError('Invalid CSRF token');
}
// 토큰 재생성 (일회용)
return this.generateToken(sessionId);
}
}
// Double Submit Cookie Pattern
app.use((req, res, next) => {
const token = req.cookies.csrfToken || crypto.randomBytes(32).toString('hex');
res.cookie('csrfToken', token, { httpOnly: false, sameSite: 'strict' });
req.csrfToken = token;
next();
});
```
```javascript
class OAuth2Provider {
// Authorization Code Flow
async authorize(clientId, redirectUri, scope) {
// 1. 사용자 인증
const user = await this.authenticateUser();
// 2. 클라이언트 검증
const client = await this.validateClient(clientId, redirectUri);
// 3. 권한 부여 코드 생성
const code = crypto.randomBytes(32).toString('hex');
await this.storeAuthCode(code, {
clientId,
userId: user.id,
scope,
expiresAt: Date.now() + 600000 // 10분
});
return code;
}
// Token Exchange
async exchangeToken(code, clientId, clientSecret) {
const authCode = await this.getAuthCode(code);
// 검증
if (!authCode || authCode.clientId !== clientId) {
throw new Error('Invalid authorization code');
}
if (Date.now() > authCode.expiresAt) {
throw new Error('Authorization code expired');
}
// 토큰 생성
const accessToken = this.generateJWT(authCode.userId, authCode.scope);
const refreshToken = crypto.randomBytes(32).toString('hex');
await this.storeRefreshToken(refreshToken, authCode.userId);
await this.revokeAuthCode(code);
return { accessToken, refreshToken };
}
}
```
```javascript
class SecureJWT {
constructor() {
this.algorithm = 'RS256'; // 비대칭 키 사용
this.issuer = 'secure-app';
this.audience = 'api.secure-app.com';
}
generateToken(payload) {
const token = jwt.sign(payload, this.privateKey, {
algorithm: this.algorithm,
expiresIn: '15m', // 짧은 만료 시간
issuer: this.issuer,
audience: this.audience,
jwtid: uuidv4() // 토큰 ID로 재사용 방지
});
return token;
}
verifyToken(token) {
try {
const decoded = jwt.verify(token, this.publicKey, {
algorithms: [this.algorithm],
issuer: this.issuer,
audience: this.audience
});
// 토큰 블랙리스트 확인
if (this.isBlacklisted(decoded.jti)) {
throw new Error('Token revoked');
}
return decoded;
} catch (error) {
throw new SecurityError('Invalid token: ' + error.message);
}
}
}
```
```javascript
class AESEncryption {
constructor(key) {
this.algorithm = 'aes-256-gcm';
this.key = Buffer.from(key, 'hex');
}
encrypt(plaintext) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex')
};
}
decrypt(encryptedData) {
const decipher = crypto.createDecipheriv(
this.algorithm,
this.key,
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
```
```javascript
class RSAEncryption {
generateKeyPair() {
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: process.env.KEY_PASSPHRASE
}
});
return { publicKey, privateKey };
}
encrypt(data, publicKey) {
const buffer = Buffer.from(data, 'utf8');
const encrypted = crypto.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256'
},
buffer
);
return encrypted.toString('base64');
}
decrypt(encryptedData, privateKey) {
const buffer = Buffer.from(encryptedData, 'base64');
const decrypted = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
passphrase: process.env.KEY_PASSPHRASE
},
buffer
);
return decrypted.toString('utf8');
}
}
```
```javascript
// HTTPS 서버 설정
const https = require('https');
const tls = require('tls');
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
// 보안 강화 설정
secureOptions: tls.constants.SSL_OP_NO_TLSv1 |
tls.constants.SSL_OP_NO_TLSv1_1,
ciphers: [
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-SHA256',
'ECDHE-RSA-AES256-SHA384'
].join(':'),
honorCipherOrder: true,
// HSTS
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
};
https.createServer(options, app).listen(443);
```
```bash
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --syn -m limit --limit 25/s --limit-burst 50 -j ACCEPT
```
```javascript
class AnomalyDetector {
constructor() {
this.baseline = new Map();
this.threshold = 2.5; // 표준편차 배수
}
// 사용자 행동 분석
analyzeUserBehavior(userId, action) {
const userBaseline = this.baseline.get(userId) || {
loginTimes: [],
ipAddresses: new Set(),
requestRate: []
};
// 로그인 시간 이상 탐지
if (action.type === 'login') {
const hour = new Date(action.timestamp).getHours();
const avgHour = average(userBaseline.loginTimes);
const stdDev = standardDeviation(userBaseline.loginTimes);
if (Math.abs(hour - avgHour) > stdDev * this.threshold) {
this.alertSuspiciousLogin(userId, action);
}
}
// IP 주소 변경 탐지
if (!userBaseline.ipAddresses.has(action.ipAddress)) {
this.alertNewLocation(userId, action);
}
// 요청 빈도 이상 탐지
const requestsPerMinute = this.calculateRequestRate(userId);
if (requestsPerMinute > userBaseline.avgRate * this.threshold) {
this.alertHighRequestRate(userId, requestsPerMinute);
}
}
}
```
```javascript
class SecurityEventCorrelator {
correlateEvents(events) {
const patterns = {
bruteForce: this.detectBruteForce(events),
privilegeEscalation: this.detectPrivilegeEscalation(events),
dataExfiltration: this.detectDataExfiltration(events),
lateralMovement: this.detectLateralMovement(events)
};
return patterns;
}
detectBruteForce(events) {
const failedLogins = events.filter(e =>
e.type === 'login_failed' &&
e.timestamp > Date.now() - 300000 // 5분
);
const attempts = {};
failedLogins.forEach(event => {
const key = `${event.username}:${event.ipAddress}`;
attempts[key] = (attempts[key] || 0) + 1;
});
return Object.entries(attempts)
.filter(([_, count]) => count > 5)
.map(([key, count]) => ({
type: 'brute_force',
target: key.split(':')[0],
source: key.split(':')[1],
attempts: count
}));
}
}
```
```javascript
class GDPRCompliance {
// 동의 관리
async recordConsent(userId, purposes) {
const consent = {
userId,
purposes,
timestamp: new Date().toISOString(),
ipAddress: getClientIP(),
version: 'v1.2'
};
await this.store.saveConsent(consent);
return consent;
}
// 데이터 이동권
async exportUserData(userId) {
const data = {
profile: await this.getUserProfile(userId),
activities: await this.getUserActivities(userId),
preferences: await this.getUserPreferences(userId),
consents: await this.getUserConsents(userId)
};
// 민감한 정보 마스킹
data.profile = this.maskSensitiveData(data.profile);
return {
exportDate: new Date().toISOString(),
format: 'json',
data: data
};
}
// 삭제권 (잊혀질 권리)
async deleteUserData(userId) {
// 감사 로그 생성
await this.auditLog.record({
action: 'user_data_deletion',
userId,
timestamp: new Date().toISOString(),
reason: 'GDPR Article 17 Request'
});
// 데이터 삭제 (보존 의무가 있는 데이터 제외)
await Promise.all([
this.deleteProfile(userId),
this.deleteActivities(userId),
this.deletePreferences(userId),
this.anonymizeTransactions(userId)
]);
}
}
```
```javascript
class SecurityScanner {
async runSecurityChecks() {
const results = {
timestamp: new Date().toISOString(),
vulnerabilities: []
};
// 의존성 취약점 검사
const npmAudit = await this.runNpmAudit();
results.vulnerabilities.push(...npmAudit);
// 보안 헤더 검사
const headers = await this.checkSecurityHeaders();
results.vulnerabilities.push(...headers);
// SSL/TLS 설정 검사
const ssl = await this.checkSSLConfiguration();
results.vulnerabilities.push(...ssl);
// 설정 파일 검사
const config = await this.checkConfigurationFiles();
results.vulnerabilities.push(...config);
return results;
}
async checkSecurityHeaders() {
const requiredHeaders = [
'Strict-Transport-Security',
'X-Frame-Options',
'X-Content-Type-Options',
'Content-Security-Policy',
'X-XSS-Protection'
];
const response = await fetch(this.targetUrl);
const missing = requiredHeaders.filter(header =>
!response.headers.has(header)
);
return missing.map(header => ({
severity: 'medium',
type: 'missing_security_header',
details: `Missing header: ${header}`
}));
}
}