무료 챕터
7. 보안과 성능 최적화
by leancle•2025. 8. 9.
🔒 MCP 환경의 보안 강화
MCP는 강력하지만, 잘못 사용하면 보안 위험이 될 수 있습니다. 안전한 MCP 환경을 구축하는 방법을 알아봅니다.
🛡️ 보안 설정
읽기 전용 모드 설정
{
"mcpServers": {
"supabase-prod": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--read-only", // 중요: 프로덕션은 항상 읽기 전용
"--project-ref=prod-project-ref"
],
"env": {
"SUPABASE_ACCESS_TOKEN": "prod-token"
}
}
}
}
RLS (Row Level Security) 정책
You: "모든 테이블에 적절한 RLS 정책을 설정해줘"
Claude: 각 테이블에 보안 정책을 설정하겠습니다.
[MCP 실행 중...]
```sql
-- users 테이블 RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own profile" ON users
FOR SELECT USING (auth.uid() = id);
CREATE POLICY "Users can update own profile" ON users
FOR UPDATE USING (auth.uid() = id);
-- orders 테이블 RLS
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can view own orders" ON orders
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can create own orders" ON orders
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- products 테이블 RLS (공개 읽기)
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Anyone can view products" ON products
FOR SELECT USING (true);
CREATE POLICY "Only admins can modify products" ON products
FOR ALL USING (
EXISTS (
SELECT 1 FROM users
WHERE id = auth.uid() AND role = 'admin'
)
);
✅ RLS 정책이 적용되었습니다.
## ⚡ 성능 최적화
### 인덱스 최적화
You: "쿼리 성능을 분석하고 필요한 인덱스를 추가해줘"
Claude: 쿼리 패턴을 분석하고 인덱스를 최적화하겠습니다.
[MCP로 쿼리 분석 중...]
📊 분석 결과:
- 느린 쿼리 발견: 5개
- 누락된 인덱스: 8개
- 중복 인덱스: 2개
-- 자주 사용되는 검색 필드에 인덱스 추가
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created_at ON users(created_at DESC);
-- 복합 인덱스 (JOIN 최적화)
CREATE INDEX idx_orders_user_id_created_at
ON orders(user_id, created_at DESC);
-- 부분 인덱스 (조건부 쿼리 최적화)
CREATE INDEX idx_orders_pending
ON orders(created_at DESC)
WHERE status = 'pending';
-- 텍스트 검색 인덱스
CREATE INDEX idx_products_search
ON products USING gin(to_tsvector('english', name || ' ' || description));
-- 중복 인덱스 제거
DROP INDEX IF EXISTS redundant_index_1;
DROP INDEX IF EXISTS redundant_index_2;
✅ 예상 성능 향상: 평균 85%
### 쿼리 최적화
You: "N+1 문제가 있는 쿼리를 찾아서 최적화해줘"
Claude: N+1 쿼리 패턴을 감지하고 최적화하겠습니다.
[MCP로 쿼리 로그 분석 중...]
⚠️ N+1 문제 발견:
Before (N+1 문제):
// 사용자별로 주문을 개별 조회 (비효율적)
const users = await supabase.from('users').select('*');
for (const user of users.data) {
const orders = await supabase
.from('orders')
.select('*')
.eq('user_id', user.id);
user.orders = orders.data;
}
// 총 쿼리: 1 + N개 (N = 사용자 수)
After (최적화):
// JOIN으로 한 번에 조회
const { data } = await supabase
.from('users')
.select(`
*,
orders (*)
`);
// 총 쿼리: 1개
성능 개선: 쿼리 수 95% 감소, 응답 시간 80% 단축
## 🔐 환경 변수 관리
### 안전한 토큰 관리
You: "환경별로 안전하게 토큰을 관리하는 방법을 보여줘"
Claude: 환경별 보안 설정 가이드를 제공하겠습니다.
.env.local (개발):
# 개발 환경 (Git 제외)
SUPABASE_URL=https://dev-project.supabase.co
SUPABASE_ANON_KEY=eyJ...dev...
SUPABASE_SERVICE_KEY=eyJ...dev-service...
SUPABASE_ACCESS_TOKEN=sbp_dev_token
MCP_READ_ONLY=false
.env.production (프로덕션):
# 프로덕션 환경 (환경 변수로 주입)
SUPABASE_URL=${PROD_SUPABASE_URL}
SUPABASE_ANON_KEY=${PROD_SUPABASE_ANON_KEY}
SUPABASE_SERVICE_KEY=${PROD_SUPABASE_SERVICE_KEY}
SUPABASE_ACCESS_TOKEN=${PROD_SUPABASE_ACCESS_TOKEN}
MCP_READ_ONLY=true # 항상 true
토큰 로테이션 스크립트:
// scripts/rotate-tokens.js
const { createClient } = require('@supabase/supabase-js');
async function rotateTokens() {
// 1. 새 토큰 생성
const newToken = await generateNewToken();
// 2. 환경 변수 업데이트
await updateEnvironmentVariable('SUPABASE_ACCESS_TOKEN', newToken);
// 3. 이전 토큰 무효화 (24시간 후)
setTimeout(() => revokeOldToken(oldToken), 24 * 60 * 60 * 1000);
console.log('✅ 토큰 로테이션 완료');
}
// 매월 실행
cron.schedule('0 0 1 * *', rotateTokens);
📈 모니터링과 로깅
MCP 활동 모니터링
You: "MCP 서버의 모든 활동을 로깅하고 모니터링하는 시스템을 만들어줘"
Claude: MCP 활동 모니터링 시스템을 구현하겠습니다.
**lib/mcp-monitor.ts:**
```typescript
import { createClient } from '@supabase/supabase-js';
interface MCPActivity {
timestamp: Date;
action: string;
query?: string;
result?: any;
error?: string;
duration: number;
userId?: string;
}
class MCPMonitor {
private activities: MCPActivity[] = [];
async logActivity(activity: MCPActivity) {
// 메모리에 저장
this.activities.push(activity);
// 데이터베이스에 기록
await supabase
.from('mcp_audit_log')
.insert([{
...activity,
timestamp: activity.timestamp.toISOString()
}]);
// 이상 감지
this.detectAnomalies(activity);
}
private detectAnomalies(activity: MCPActivity) {
// 위험한 쿼리 패턴 감지
const dangerousPatterns = [
/DELETEs+FROM/i,
/DROPs+TABLE/i,
/TRUNCATE/i,
/UPDATE.*SET.*WHEREs+1=1/i
];
if (activity.query) {
for (const pattern of dangerousPatterns) {
if (pattern.test(activity.query)) {
this.sendAlert({
level: 'critical',
message: `위험한 쿼리 감지: ${activity.query}`,
timestamp: activity.timestamp
});
}
}
}
// 비정상적인 활동량 감지
const recentActivities = this.activities.filter(
a => a.timestamp > new Date(Date.now() - 60000) // 1분
);
if (recentActivities.length > 100) {
this.sendAlert({
level: 'warning',
message: `비정상적인 활동량: 1분간 ${recentActivities.length}개 쿼리`,
timestamp: new Date()
});
}
}
private async sendAlert(alert: any) {
// Slack, Discord, 이메일 등으로 알림
console.error('🚨 보안 알림:', alert);
// 위험 수준에 따라 MCP 서버 중지
if (alert.level === 'critical') {
await this.emergencyShutdown();
}
}
private async emergencyShutdown() {
console.error('⛔ 긴급 MCP 서버 중지');
process.exit(1);
}
}
🎉 완료!
이제 안전하고 빠른 MCP 환경이 구축되었습니다!
📚 다음 챕터 예고
"프로덕션 배포와 스케일링" - MCP를 프로덕션 환경에 안전하게 배포하고 대규모 트래픽을 처리하는 방법!