fix: Critical 보안 이슈 4건 수정
1. SQL injection 취약점 수정 (currency 직접 삽입 제거) - SQL 쿼리에서 currency 제거, 결과 매핑에서 추가 2. 에러 메시지 정보 노출 수정 - 클라이언트에 내부 에러 상세 숨김 - 서버 로그에만 기록 3. API 키 로깅 제거 - sk-*** 형식만 표시, 실제 값 노출 안함 4. Rate limit fail-closed 정책 적용 - KV 오류 시 요청 거부 (보안 강화) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
19
src/index.ts
19
src/index.ts
@@ -635,8 +635,8 @@ async function checkRateLimit(clientIP: string, env: Env): Promise<{ allowed: bo
|
||||
return { allowed: true, requestId };
|
||||
} catch (error) {
|
||||
console.error('[RateLimit] KV error:', error);
|
||||
// On error, allow the request (fail open)
|
||||
return { allowed: true, requestId };
|
||||
// On error, deny the request (fail closed) for security
|
||||
return { allowed: false, requestId };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1077,10 +1077,10 @@ async function handleRecommend(
|
||||
} catch (error) {
|
||||
console.error('[Recommend] Error:', error);
|
||||
console.error('[Recommend] Error stack:', error instanceof Error ? error.stack : 'No stack');
|
||||
console.error('[Recommend] Error details:', error instanceof Error ? error.message : 'Unknown error');
|
||||
return jsonResponse(
|
||||
{
|
||||
error: 'Failed to generate recommendations',
|
||||
details: error instanceof Error ? error.message : 'Unknown error',
|
||||
request_id: requestId,
|
||||
},
|
||||
500,
|
||||
@@ -1303,7 +1303,6 @@ async function queryCandidateServers(
|
||||
it.gpu_count,
|
||||
it.gpu_type,
|
||||
MIN(${priceColumn}) as monthly_price,
|
||||
'${currency}' as currency,
|
||||
r.region_name as region_name,
|
||||
r.region_code as region_code,
|
||||
r.country_code as country_code
|
||||
@@ -1436,8 +1435,14 @@ async function queryCandidateServers(
|
||||
throw new Error('Failed to query candidate servers');
|
||||
}
|
||||
|
||||
// Validate each result with type guard
|
||||
const validServers = (result.results as unknown[]).filter(isValidServer);
|
||||
// Add currency to each result and validate with type guard
|
||||
const serversWithCurrency = (result.results as unknown[]).map(server => {
|
||||
if (typeof server === 'object' && server !== null) {
|
||||
return { ...server, currency };
|
||||
}
|
||||
return server;
|
||||
});
|
||||
const validServers = serversWithCurrency.filter(isValidServer);
|
||||
const invalidCount = result.results.length - validServers.length;
|
||||
if (invalidCount > 0) {
|
||||
console.warn(`[Candidates] Filtered out ${invalidCount} invalid server records`);
|
||||
@@ -1851,7 +1856,7 @@ async function getAIRecommendations(
|
||||
console.error('[AI] OPENAI_API_KEY has invalid format (should start with sk-)');
|
||||
throw new Error('Invalid OPENAI_API_KEY format');
|
||||
}
|
||||
console.log('[AI] API key validated (sk-***' + apiKey.slice(-4) + ')');
|
||||
console.log('[AI] API key validated (format: sk-***)');
|
||||
|
||||
// Build dynamic tech specs prompt from database
|
||||
const techSpecsPrompt = formatTechSpecsForPrompt(techSpecs);
|
||||
|
||||
Reference in New Issue
Block a user