Go에서 파일 업로드 보안: 7가지 일반적인 공격에 대응하는 방법
기존 인증이 없는 시스템에서는 파일 업로드를 위한 요청 출처 식별이 매우 중요합니다. PDF를 마크다운으로 변환하는 브라우저 확장 프로그램의 경우, WebCrypto API를 기반으로 한 ECDSA P-256 모델을 도입했습니다. 첫 실행 시, 내보낼 수 없는 키 쌍이 생성됩니다:
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
false, // extractable = false
['sign', 'verify']
);
공개키는 서버에 등록되며, device_id와 device_token을 반환합니다. 모든 API 요청에는 다음 정보가 포함됩니다:
Authorization: Bearer <token>X-Timestamp(±5분 이내)X-Nonce(재생 공격 방지)X-Body-SHA256X-Signature(METHOD+PATH+TIMESTAMP+NONCE+BODY_HASH에 대한 ECDSA 서명)
서버는 공개키를 사용해 서명을 검증함으로써 다음과 같은 보안을 확보합니다:
- 디바이스별 리밋 설정
- 재생 공격 방어
- 작업 슬롯 제어 (최대 3개 활성 작업)
- 등록 제한 (IP당 시간당 최대 5회)
이 모델은 공격 비용을 증가시켜, 전체 ECDSA 서명 구현이 필요하게 만듭니다.
공격 1: 파일 유형 위조
악성 실행 파일을 PDF처럼 위장하는 공격입니다. 방어는 세 단계로 이루어집니다.
프론트엔드: MIME 타입과 확장자 검사:
const ALLOWED_TYPES = ['application/pdf'];
const ALLOWED_EXTENSIONS = ['.pdf'];
function validateFile(file) {
const isPdf = ALLOWED_TYPES.includes(file.type) ||
ALLOWED_EXTENSIONS.some(ext =>
file.name.toLowerCase().endsWith(ext));
if (!isPdf) return { valid: false, error: 'PDF만 허용' };
}
백엔드: Content-Type 기반 라우팅. 핵심: 매직 바이트 확인:
pdfMagicBytes := "%PDF"
header4 := make([]byte, 4)
_, err := file.Read(header4)
if string(header4) != pdfMagicBytes {
respondError(w, http.StatusBadRequest,
models.ErrCodeValidationError,
"유효한 PDF가 아닙니다")
}
file.Seek(0, 0)
헤더나 확장자를 무시하고, 파일의 처음 4바이트를 직접 확인함으로써 위변조를 방지합니다. 다중 포맷 파일(악성 코드를 포함한 유효한 PDF)은 추가 서명이 필요합니다.
공격 2: 디스크 고갈 (DoS)
큰 파일을 통해 서비스 거부 공격을 시도합니다. 대응책은 다음과 같습니다:
http.MaxBytesReader(w, r.Body, MaxFileSize + 1MB)— 읽기 제한치에서 즉시 중단- 디바이스별 작업 슬롯: 최대 3개의 활성 작업 (
queued,processing,ready,error상태) - 등록 및 요청에 대한 리밋 설정
디바이스 식별이므로 IP 또는 토큰 회전 전략은 효과 없음.
공격 3: 경로 탐색 (Path Traversal)
../../../etc/passwd와 같은 경로를 이용한 공격입니다. 해결책: 고정된 경로 {UUID}/input.pdf. 사용자 입력은 경로에 전혀 반영되지 않습니다.
프론트엔드 정제 (추가 보안 계층):
function sanitizeFileName(name) {
return name
.replace(/[/\\?%*:|"<>]/g, '-')
.replace(/^\.+/, '')
.replace(/\.$/, '')
.substring(0, 255)
.trim();
}
백엔드는 파일명과 무관하게 자체적으로 경로를 생성합니다.
공격 4: URL 업로드를 통한 SSRF
"URL에서 업로드" 기능을 위해 다음 사항을 차단합니다:
- 다운로드 전 DNS 해석 금지
- 리디렉션 차단
- 개인 IP 주소 차단 (차단 목록: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
공격 5: 재생 공격 (Replay Attacks)
X-Nonce + X-Timestamp + 서명. Nonce는 디바이스별로 저장되며, 타임스탬프는 ±5분 범위 내에서만 유효합니다.
공격 6: 디바이스 위조 (Impersonation)
extractable: false 설정으로 비밀키가 외부로 추출 불가. device_token을 탈취해도 유효한 서명 없이는 무용지물입니다.
공격 7: 애플리케이션 계층 오남용
리밋 + 슬롯 제어 + 암호화 서명 적용. 최대 3개의 슬롯, IP당 시간당 최대 5회 등록 제한.
핵심 요약
- 암호화된 디바이스 식별이 리밋 설정을 위한 계정 시스템 대체
- 파일 유형 검증은 매직 바이트(
%PDF)가 유일한 신뢰할 수 있는 방법 MaxBytesReader+ 슬롯 관리로 DoS 공격 방어- 고정 경로로 경로 탐색 위험 완전 제거
- ECDSA P-256 + nonce/timestamp로 재생 및 위조 공격 차단
— Editorial Team
아직 댓글이 없습니다.