fix: 아키텍처 리뷰 HIGH/MEDIUM 이슈 10건 수정
HIGH (3건): - 런처 파일 업로드 시 PE 헤더 검증 + 500MB 크기 제한 추가 - 체인 노드 URL 파싱 시 scheme/host 유효성 검증 - Dockerfile 비루트 사용자(app:1000) 실행 MEDIUM (7건): - SSAFY username 충돌 시 랜덤 suffix로 최대 3회 재시도 - 내부 API username 검증 validID(256자) → validUsername(3~50자) 분리 - 동시 업로드 경합 방지 sync.Mutex 추가 - 프로덕션 환경변수 검증 강화 (DB_PASSWORD, OPERATOR_KEY_HEX, INTERNAL_API_KEY) - Redis 에러 시 멱등성 요청 통과 → 503 거부로 변경 - CORS AllowOrigins 환경변수화 (CORS_ALLOW_ORIGINS) - Refresh 엔드포인트 rate limiting 추가 (IP당 5 req/min) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -35,6 +36,9 @@ type Config struct {
|
||||
OperatorKeyHex string
|
||||
WalletEncryptionKey string
|
||||
|
||||
// CORS
|
||||
CORSAllowOrigins string
|
||||
|
||||
// Server-to-server auth
|
||||
InternalAPIKey string
|
||||
|
||||
@@ -72,6 +76,8 @@ func Load() {
|
||||
OperatorKeyHex: getEnv("OPERATOR_KEY_HEX", ""),
|
||||
WalletEncryptionKey: getEnv("WALLET_ENCRYPTION_KEY", ""),
|
||||
|
||||
CORSAllowOrigins: getEnv("CORS_ALLOW_ORIGINS", "https://a301.tolelom.xyz"),
|
||||
|
||||
InternalAPIKey: getEnv("INTERNAL_API_KEY", ""),
|
||||
|
||||
SSAFYClientID: getEnv("SSAFY_CLIENT_ID", ""),
|
||||
@@ -83,6 +89,9 @@ func Load() {
|
||||
if raw := getEnv("CHAIN_NODE_URLS", ""); raw != "" {
|
||||
for _, u := range strings.Split(raw, ",") {
|
||||
if u = strings.TrimSpace(u); u != "" {
|
||||
if parsed, err := url.Parse(u); err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
||||
log.Fatalf("FATAL: invalid CHAIN_NODE_URL: %q (must be http:// or https://)", u)
|
||||
}
|
||||
C.ChainNodeURLs = append(C.ChainNodeURLs, u)
|
||||
}
|
||||
}
|
||||
@@ -114,8 +123,23 @@ func WarnInsecureDefaults() {
|
||||
log.Println("WARNING: WALLET_ENCRYPTION_KEY is empty — blockchain wallet features will fail")
|
||||
}
|
||||
|
||||
if isProd {
|
||||
if C.DBPassword == "" {
|
||||
log.Println("FATAL: DB_PASSWORD must be set in production")
|
||||
insecure = true
|
||||
}
|
||||
if C.OperatorKeyHex == "" {
|
||||
log.Println("FATAL: OPERATOR_KEY_HEX must be set in production")
|
||||
insecure = true
|
||||
}
|
||||
if C.InternalAPIKey == "" {
|
||||
log.Println("FATAL: INTERNAL_API_KEY must be set in production")
|
||||
insecure = true
|
||||
}
|
||||
}
|
||||
|
||||
if isProd && insecure {
|
||||
log.Fatal("FATAL: insecure default secrets detected in production — set JWT_SECRET, REFRESH_SECRET, and ADMIN_PASSWORD")
|
||||
log.Fatal("FATAL: insecure defaults detected in production — check warnings above")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user