Foundry
파일 업로드 시스템 설계
중급
핵심

검증과 용량 제한

앱을 거치지 않는 파일을 어떻게 믿나

직접 업로드에서는 파일이 앱을 지나가지 않습니다. 그래서 검증할 자리가 사라집니다. 검증을 어디에 둘지가 이 개념의 문제입니다.

확장자는 내용이 아니다

파일 이름의 확장자는 클라이언트가 정한 문자열입니다. 보고서.pdf 라는 이름의 실행 파일을 막지 못합니다. 실제 종류는 파일 시그니처로 봅니다. 대부분의 형식은 앞부분 몇 바이트에 고유한 값이 있습니다.

검사 대상신뢰도
확장자없다. 이름만 바꾸면 통과한다
클라이언트가 보낸 콘텐츠 타입없다. 요청을 직접 만들면 통과한다
파일 시그니처있다. 실제 바이트를 본다

시그니처도 완벽하지 않습니다. 앞부분만 정상으로 위장할 수 있습니다. 그래서 이미지처럼 다시 인코딩할 수 있는 형식은 변환해서 다시 저장하는 편이 안전합니다. 변환에 성공하면 그것이 곧 검증입니다.

검사는 비동기로, 그 사이는 격리로

직접 업로드는 앱이 사후에만 볼 수 있으므로 검사가 비동기가 됩니다. 그러면 검사 전 구간이 생깁니다.

격리 영역에 올린 뒤 검사를 통과하면 공개 영역으로 옮긴다 클라이언트 격리 영역 목록에 안 보인다 검사 공개 영역 삭제하고 알린다 공개 영역에 있다는 것이 곧 통과했다는 뜻

격리 영역과 공개 영역을 나누는 것이 핵심입니다. 같은 자리에 두고 상태 컬럼으로만 구분하면, 어딘가에서 상태 확인을 빠뜨렸을 때 검사 전 파일이 노출됩니다. 경계는 코드가 아니라 저장 위치로 만드는 편이 안전합니다.

크기 제한은 서명에 박는다

앞 개념에서 본 것과 같습니다. 화면에서만 막으면 요청을 직접 만들어 우회됩니다. 서명 조건에 넣으면 스토리지가 거절합니다.

여기에 하나 더 필요합니다. 서명은 한 번의 요청을 제한하므로, 멀티파트로 파트를 계속 올리는 것은 개별 서명으로는 못 막습니다. 전체 크기 상한은 업로드 세션 단위로 따로 세야 합니다.

무엇을 검사하지 않을지도 정한다

모든 파일을 깊게 검사하면 비용과 지연이 커집니다. 요구사항에 실시간 미리보기가 없으므로, 검사를 몇 초에서 몇 분 걸리게 두고 그동안 목록에 안 보이게 하는 선택이 가능합니다. 무엇을 포기할 수 있는지가 요구사항에서 나옵니다.

면접에서 이렇게 나옵니다

Q.업로드된 파일의 종류를 어떻게 검증하나요

파일 시그니처로 봅니다. 확장자와 클라이언트가 보낸 타입은 근거가 되지 않습니다.

검사 대상신뢰도
확장자없다. 이름만 바꾸면 통과한다
클라이언트가 보낸 콘텐츠 타입없다. 요청을 직접 만들면 통과한다
파일 시그니처있다. 실제 바이트 앞부분을 본다

시그니처도 완벽하지는 않습니다. 앞부분만 정상으로 위장할 수 있습니다. 그래서 이미지처럼 다시 인코딩할 수 있는 형식은 변환해서 다시 저장하는 편이 안전합니다. 변환이 성공하면 그것이 곧 검증이고, 숨어 있던 데이터도 함께 사라집니다.

흔한 실수: 확장자 허용 목록으로 충분하다고 답하는 것. 허용 목록은 실수로 올린 파일을 걸러 주지만 의도적인 우회는 막지 못합니다. 두 목적을 구분해야 합니다.

Q.직접 업로드에서 검사 전 파일이 노출되지 않게 어떻게 막나요

격리 영역과 공개 영역을 나눕니다. 상태 컬럼만으로 구분하지 않습니다.

1) 클라이언트가 격리 영역에 올린다
2) 완료 통보를 받고 검사한다
3) 통과하면 공개 영역으로 옮긴다
4) 실패하면 지우고 알린다

같은 자리에 두고 상태 컬럼으로만 구분하면, 어딘가에서 상태 확인을 빠뜨렸을 때 검사 전 파일이 그대로 노출됩니다. 조회 경로가 여러 개면 전부에 조건을 넣어야 하고, 하나만 빠져도 구멍이 됩니다.

경계는 코드가 아니라 저장 위치로 만드는 편이 안전합니다. 공개 영역에 있다는 것 자체가 검사를 통과했다는 뜻이 됩니다.

흔한 실수: 검사를 동기로 만들어 업로드 응답을 늦추는 것. 직접 업로드는 앱이 사후에만 보므로 애초에 동기 검사가 불가능하고, 억지로 맞추면 앱을 다시 경로에 넣는 셈입니다.

Q.멀티파트 업로드에서 전체 크기 제한을 어떻게 거나요

업로드 세션 단위로 따로 셉니다. 파트별 서명으로는 막을 수 없습니다.

서명은 한 번의 요청을 제한합니다. 파트 하나에 10MB 상한을 걸어도, 파트를 계속 올리면 전체 크기는 얼마든 커집니다.

제한 위치막는 것못 막는 것
파트 서명 조건파트 하나가 너무 큰 것파트를 많이 올리는 것
업로드 세션 누적전체 크기

그래서 업로드를 시작할 때 선언한 크기를 기록하고, 파트 서명을 발급할 때마다 누적을 확인해 초과하면 더 발급하지 않습니다. 선언 크기 자체도 서버 정책과 대조합니다.

흔한 실수: 파트 개수 상한으로 대신하려는 것. 파트 크기가 가변이면 개수 상한이 전체 크기를 정하지 않습니다. 세야 하는 것은 바이트입니다.

Q.검증을 어디까지 할지는 무엇으로 정하나요

요구사항입니다. 무엇을 포기할 수 있는지가 검증 깊이를 정합니다.

모든 파일을 깊게 검사하면 비용과 지연이 커집니다. 이 서비스는 실시간 미리보기가 범위 밖이라, 검사가 몇 초에서 몇 분 걸려도 됩니다. 그동안 목록에 안 보이면 사용자는 눈치채지 못합니다.

요구사항가능한 선택
업로드 직후 미리보기가 필요하다빠른 검사만. 깊은 검사는 뒤로
늦게 보여도 된다격리 후 충분히 검사하고 공개
외부에 공유되는 파일공유 시점에 한 번 더 확인

흔한 실수: 검증을 보안 요구로만 보고 최대한 깊게 하려는 것. 검증은 지연과 비용을 쓰는 선택이고, 그 예산은 요구사항에서 나옵니다. 무엇을 검사하지 않을지 말할 수 있어야 설계가 끝난 것입니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

파일 업로드 시스템 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.