본문 바로가기
사이드 프로젝트/캡처 이미지 정리 웹 사이트 프로젝트

[대용량 이미지 태깅]대용량 이미지 업로드를 위한 Presigned URL 사용과 CORS 에러 해결 과정

by Baley 2024. 12. 22.

사용자가 평소에 저장만 하고 다시 보지 않는 캡처 이미지에서 정보를 추출하고 정리하는 Django + Python를 통해 구현하고자 한다.

 

목표과 방법

목표

대용량 이미지 업로드 시스템을 구축하는 것이 목표였다. 서버 부하를 줄이고, 업로드 속도를 최적화하면서 보안도 강화해야 했다. 이를 위해 Presigned URL을 사용하기로 했다.

Presigned URL?

Presigned URL은 AWS S3에서 제공하는 기능으로, 클라이언트가 서버를 거치지 않고 S3에 직접 파일을 업로드하거나 다운로드할 수 있도록 임시 권한을 부여하는 URL이다. 이 URL은 만료 시간과 접근 권한이 포함되어 있어, 지정된 시간 이후에는 접근이 불가능하다.

  1. 임시 접근 권한: URL은 생성 시점에 설정된 시간까지만 유효하다.
  2. 제한된 권한: 업로드, 다운로드, 삭제 등 특정 작업만 허용할 수 있다.
  3. 보안 강화: 서버 자격 증명 노출 없이 안전한 업로드가 가능하다.

왜 Presigned URL인가?

기존 방식에서는 클라이언트가 서버로 파일을 전송한 후, 서버가 다시 S3로 업로드하는 구조였다. 이 방식은 서버가 중간에서 파일을 처리하므로 트래픽 부담이 크고, 대용량 파일의 경우 업로드 지연이나 타임아웃 문제가 발생할 수 있었다.

Presigned URL은 이러한 문제를 해결하기 위해 선택되었다. 클라이언트가 서버를 거치지 않고 S3에 직접 업로드할 수 있서버 부하를 줄이고 업로드 속도를 높이고 대규모 트래픽도 안정적으로 처리할 수 있다. 또한 Presigned URL 방식이 구현에 용이하며 시간이 지나면 권한이 자동으로 만료되므로 보안 측면에서 유리하다.

 

문제 발생

Presigned URL 생성까지는 순조로웠으나 클라이언트에서 업로드를 시도했을 때, CORS 오류가 발생했다.

CORS 에러

Access to XMLHttpRequest has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.

이 문제는 업로드 요청이 브라우저의 보안 정책에 의해 차단되었음을 의미한다.

 

 

의문

Presigned URL은 단순히 임시 권한을 제공하는 역할을 한다. 그 자체로 CORS 설정을 관리하지는 않는다. 그렇다면 문제가 URL 자체에 있는 것인지, 아니면 S3 설정이나 클라이언트 요청에서 발생한 것인지 구분할 필요가 있었다.

 

해결 과정

가설 1. Presigned URL의 설정 문제

우선 Presigned URL 자체의 설정을 점검했다. 요청 시 Content-Type과 URL 생성 시 메타데이터가 일치하지 않을 경우 오류가 발생할 수 있다는 점에 주목했다.

시도

  • Presigned URL 생성 시 Content-Type을 명시했다.
  • 클라이언트 요청에도 동일한 Content-Type을 지정했다.

Content Type 명시

결과

CORS 오류는 여전히 해결되지 않았다. Presigned URL 자체에는 문제가 없었다.

 

 

가설 2. S3의 CORS 설정 문제

다음으로 S3 버킷의 CORS 설정을 점검했다. CORS는 클라이언트가 브라우저에서 외부 리소스에 접근할 수 있도록 허용하는 규칙을 정의한다.

시도

S3 버킷에 다음과 같은 CORS 정책을 적용했다.

{
  "CORSRules": [
    {
      "AllowedOrigins": ["*"],
      "AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
      "AllowedHeaders": ["*"],
      "ExposeHeaders": ["ETag"],
      "MaxAgeSeconds": 3000
    }
  ]
}

정책 적용 후 브라우저 캐시를 초기화하고 테스트를 진행했다.

결과

여전히 CORS 오류가 발생했다. S3 설정만으로는 문제가 해결되지 않았다.

 

 

가설 3. 브라우저 캐시 및 테스트 환경 문제

설정은 올바르게 적용되었지만, 브라우저가 이전의 캐시된 정책을 사용하고 있을 가능성을 검토했다.

시도

  • 브라우저 캐시와 쿠키를 모두 삭제했다.
  • 다른 브라우저와 네트워크 환경에서 테스트했다.

결과

일부 환경에서는 문제가 해결되었지만, 일관된 성공을 보장하지는 못했다.

 

 

가설 4.  요청과 설정의 불일치

마지막으로, Presigned URL과 클라이언트 요청의 설정이 불일치했을 가능성을 점검했다. 구체적으로는 다음 요소들을 확인했다.

1. URL 구성 불일치

  • 리전(Region) 불일치 - URL 생성 시 지정한 리전과 S3 버킷의 실제 리전이 다르면 요청이 실패할 수 있다. 이 경우 URL 생성 시 리전을 정확히 설정해야 한다. 리전 정보는 Presigned URL의 호스트 이름이나 경로에 포함된 요소로, URL 구성의 일부이다. 내 경우가 이러했다.
  • 프로토콜 불일치 - URL이 HTTPS로 생성되었지만 클라이언트 요청이 HTTP로 이루어졌을 가능성. 보안을 위해 HTTPS를 강제 적용해야 한다.

2. 헤더 설정 불일치

  • Content-Type 불일치 - URL 생성 시 Content-Type을 'image/jpeg'로 설정했으나 클라이언트가 'application/octet-stream'으로 요청을 보냈을 수 있다. 이 경우 Presigned URL의 메타데이터와 클라이언트 요청 헤더가 일치해야 한다.
  • Content-Length 불일치 - 업로드 파일 크기와 Content-Length 헤더가 다를 경우 요청이 거부될 수 있다. 정확한 크기를 명시해야 한다.

이러한 설정 불일치들은 Presigned URL과 클라이언트 요청 간의 충돌을 유발할 수 있으므로, 생성과 요청 단계에서 일관된 구성을 검증해야 한다.

 

시도

  • URL 생성과 요청의 헤더를 정확히 일치시켰다.
  • HTTPS로만 접근하도록 URL을 강제했다.

결과

이후 테스트에서 CORS 오류가 해결되었고, 정상적으로 업로드가 이루어졌다.

 

 

결론 및 다음 단계

결론

Presigned URL을 이용한 대용량 이미지 업로드 시스템 구축은 예상보다 복잡한 과정이었다. CORS 문제는 Presigned URL의 기능 자체가 아니라, S3 설정과 클라이언트 요청의 불일치에서 비롯된 문제였다. 이를 해결하면서 Presigned URL의 장점을 온전히 활용할 수 있는 기반을 만들었다.

다음 단계

  • 업로드 성공 이후, 비동기 처리를 추가하여 이미지 분석 및 태그 추출 기능을 구현할 계획이다

 


https://ap-northeast-2.console.aws.amazon.com/s3/bucket/insight-link-bucket/property/cors/edit?region=ap-northeast-2&bucketType=general

https://cometruedream.tistory.com/147

댓글