AWS S3 CORS(동일 출처 정책) Error

2020. 1. 23. 14:34Trouble Shooting

AWS S3를 사용하여 Image등의 media(미디어) 파일들을 처리할 경우 빈번하게 아래와 같은 오류를 만날 수 있습니다.

 

Access to image at '' from origin '' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

 

위 오류는 여러가지 제시사항이 존재하는데, 이러한 오류를 해결하기 위한 문제와 해결방안을 알아보자면,

 

  • AWS S3 CORS 설정
  • 수신(요청)하는 서버 설정
  • AWS S3 버킷 정책
  • Javascript / HTML의 Canvas

 

 

AWS S3 CORS 설정

 

가장 첫번째로 확인해야할 사항은 AWS S3에서 제공하는 CORS 정책입니다.

 

AWS S3 메뉴 구성 - CORS 구성

 

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

위 와 같이 설정할 경우 모든 도메인의 대한 동일 출처 정책을 허용하게되며,

3000초라는 캐싱 시간을 가지게 됩니다.  

당연히 업로드된 파일이 모두 허용되며, 파일들이 퍼블릭(공개, 모두접근) 권한일 경우

익명의 유저들도 URL만 알고 있다면 모두 접근할 수 있습니다.

 

 

 

 

 

수신(요청)하는 서버 설정

 

대표적으로 설정하는 서버 설정으로는 Nginx, Apache, PHP가 대개일텐데,

 

 

Nginx

Nginx의 경우 다음과 같이 Header에 직접적으로 설정하여 관여할 수 있습니다.

add_header Access-Control-Allow-Origin *;

Proxy를 통해 서비스하는 경우

 

server {
    server_name overmap.me

    charset utf-8;

    client_max_body_size 100m;
    client_body_buffer_size 52m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

    location = /favicon.ico { access_log off; log_not_found off; expires max; }

    location / {
        add_header Access-Control-Allow-Origin *;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        #proxy_pass http://172.17.0.1:9999;
        proxy_pass http://192.168.1.112:9999;
        proxy_connect_timeout 75s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
        send_timeout 300s;
    }
}

proxy_set_header Host $http_host; 를 명시함으로써 자연스럽게 헤더 전달이 이루어지는것을 볼 수 있습니다.

 

 

 

 

 

Apache2

Apache 설정에도 크게 다른 부분은 존재하지 않습니다.

<IfModule mod_headers.c>
	Header set Access-Control-Allow-Origin "*"
</IfModule>

위 와 같이 header를 직접적으로 명시함으로써 동일출처 정책을 허용합니다.

 

 

 

 

 

PHP

php내에서도 직접적으로 header를 명시하여 설정하는 방법이 존재합니다.

 

<?php
header("Access-Control-Allow-Origin: *");
?>

Nginx, Apache와 똑같이 header에 직접 명시를 할 수 있습니다.

 

 

 

 

AWS S3 버킷 정책

 

버킷정책은 사실 파일들에 대한 접근 권한을 의미하는 부분이며, 이로 인해 접근이 안되는건

S3에 직접 연결이 가능하냐 불가능하냐로 갈립니다.

 

Public의 경우 무의미하기 때문에 크게 영향을 미치진 않습니다.

 

 

 

 

 

 

Javascript / HTML의 Canvas

 

HTML에서 img 태그를 통해 보여줄 경우 제일처음 언급했던 오류가 나타날 가능성이 매우 큽니다.

이러한 경우 2가지 해결책을 가지게 됩니다.

 

 

crossorigin

<img src="<URL>" crossorigin="anonymous">

위 처럼 crossorigin 즉 동일출처정책에 대해서 익명으로 접근하겠다고 명시합니다.

특이점이 존재하긴 하는데, SSL을 뺄 경우 표기되는경우도 존재하긴 합니다.

 

하지만 문제는 여기서 그치지않고, 

javascript를 통해 이미지를 다운로드 할 경우 발생합니다.

 

 

Canvas

html2canvas, getBlobFromURL 등을 사용하여 수신한 S3의 이미지들을

canvas로 재구성할 때 Cross Origin에 위협을 받습니다.

 

이는 굉장히 큰 이슈로 나타났었는데, AWS측에서는 Chrome의 캐싱 버그다!

구글측에서는 AWS S3의 문제다 우린 이상없다!

 

라고 하니 유저들은 이를 해결하기 위해

https://test.s3.ap-northeast-2.amazonaws.com/image.png?timestamp=2

위 처럼 GET 인자로 무의미한 값이나 timestamp를 추가하여 요청할때 마다 다른 URL을 사용해서

Origin을 추가하는 방식을 사용해 이 문제를 해결했다고 합니다.