초보자를 위한 AWS: S3, 중복 제거(Deduplication), 그리고 Presigned URL

장난감 같은 앱은 그만 만드세요. 이제 실제 운영 환경(production)을 위한 시스템을 구축해야 합니다.

서버가 언제든 교체될 수 있는 구조라면, 파일이 서버 디스크에 저장되어서는 안 됩니다. AWS S3가 필요합니다. S3는 객체 스토리지(object storage)입니다. 서버와 독립적으로 존재하므로, 서버가 충돌하거나 사라지더라도 파일이 안전하게 보존됩니다.

전문적인 파일 업로드 흐름을 구축하는 방법은 다음과 같습니다:

  • S3 Bucket과 Key 사용하기 Bucket은 컨테이너 역할을 합니다. Key는 파일의 전체 경로입니다. S3에는 실제 폴더가 없습니다. 대신 평면적인 구조(flat structure)에서 접두사(prefix)를 사용합니다. images/documents/와 같이 파일 유형별로 접두사를 지정하여 깔끔하게 정리할 수 있습니다.

  • 콘텐츠 중복 제거(Content Deduplication) 구현하기 동일한 파일에 대해 비용을 이중으로 지불하지 마세요. SHA-256 알고리즘을 사용하여 모든 파일에 대한 고유한 지문(fingerprint)을 생성하세요. 두 사용자가 정확히 같은 이미지를 업로드하면 해시(hash) 값도 동일합니다. S3에 업로드하기 전에 데이터베이스에서 이 해시 값이 있는지 확인하세요. 해시가 이미 존재한다면 기존 파일을 재사용하면 됩니다.

  • 대용량 파일 스트리밍 해시 값을 생성하기 위해 200MB짜리 영상을 서버 RAM에 통째로 올리지 마세요. Node.js streams를 사용하여 파일을 작은 청크(chunk) 단위로 처리하세요. 이렇게 하면 서버 속도를 유지하고 충돌을 방지할 수 있습니다.

  • 파일 크기 제한 강제하기 프론트엔드에서의 체크는 사용자 경험(UX)을 위한 것일 뿐, 보안책이 아닙니다. 다음 세 가지 계층에서 크기 제한을 반드시 적용해야 합니다: • UX를 위한 클라이언트 측(Client-side) 제한. • 잘못된 요청을 조기에 차단하기 위한 백엔드 검증. • 업로드 시작 단계에서 용량이 초과된 업로드를 차단하기 위한 Presigned URL을 통한 S3 조건 설정.

  • 보안을 위해 Presigned URL 사용하기 Bucket을 공개(public)로 설정하지 마세요. "Block all public access" 설정을 켜두어야 합니다. 대신 Presigned URL을 생성하세요. 이를 통해 사용자에게 특정 파일 하나를 업로드할 수 있는 일시적인 권한을 부여할 수 있습니다. 만료 시간(expiry time)을 설정할 수도 있습니다. 작은 파일에는 짧은 유효 시간을, 대용량 영상 업로드에는 더 긴 유효 시간을 설정하세요.

  • 업로드 확인하기 클라이언트를 절대 믿지 마세요. 업로드 후에는 HeadObject 명령을 사용하여 파일이 실제로 S3에 존재하는지, 그리고 크기가 기록된 데이터와 일치하는지 확인하세요.

운영 환경의 흐름(The Production Flow):

  1. 클라이언트가 업로드 URL을 요청합니다.
  2. 백엔드에서 크기, 유형을 검증하고 중복 여부를 확인합니다.
  3. 백엔드에서 권한이 제한된(scoped) Presigned URL을 생성합니다.
  4. 클라이언트가 S3로 파일을 직접 업로드합니다.
  5. 백엔드가 HeadObject를 통해 파일이 존재하는지 확인합니다.

기본적으로 보안이 확보된(secure by default) 시스템을 구축하세요.

출처: https://dev.to/surajrkhonde/aws-for-newbies-episode-2-3jg5