Flask에서 Cors Error 해결방법

2021. 10. 7. 01:39

CORS ERROR

Access to XMLHttpRequest at '주소A' from origin '주소B' has been blocked by CORS policy: Np 'Access-Control-Allow-Origin' header is present on the requested resource.

 

1. CORS(교차 출처 리소스 공유)란?

CORS는 Cross-Origin Resource Shaging의 약어로, 말 그대로 다른 출처끼리의 리소스 공유를 뜻한다. 따라서 CORS 에러는 출처가 다른 리소스에 접근하려고 할 때 브라우저가 보안상의 이유로 이 접근을 막으면서 발생한다.

 

여기서 출처란 무엇일까?

1-1) Origin(출처)

Origin(출처)는 URL의 구성요소 중에서도 스킴(프로토콜), 호스트(도메인), 포트로 정의된다.

이미지 출처

 

Origin은 프로토콜, 주소, 포트번호의 쌍을 말한다.

즉, Origin = [프로토콜]://[host주소]:[포트번호]

다른 Origin이란 프로토콜(HTTP, HTTPS)가 다르거나 주소(tistory.com, naver.com)이 다르거나 포트번호(80, 5000)이 다르다는 뜻이다.

 

(1) 출처가 같은 URL 예시

왜 같은 Origin일까?

http://domain-a.com/app1/index.html
http://domain-a.com/app1/index.html
스킴(http)과 호스트(domain-a) 일치
http://domain-a.com:80
http://domain-a.com
HTTP의 기본 포트는 80

(2) 출처가 다른 URL 예시

왜 다른 Origin일까?

http://domain-a.com/app1/index.html
https://domain-a.com/app1/index.html
스킴 불일치
http://domain-a.com/app1/index.html
http://domain-b.com/app1/index.html
http://lala/app1/index.html
호스트 불일치
http://domain-a.com:80
http://domain-a.com:8080
포트 불일치

 

1-2) SOP(Same-Origin Policy), 동일 출처 정책

말 그대로, "같은 출처에서만 리소스를 공유할 수 있다"는 정책이다. 브라우저에서는 기본적으로 SOP를 통해 보안을 유지한다.

하지만 같은 출처끼리만 리소스를 공유하는 일은 사실상 불가능하다. 예를 들어 백엔드를 서버를 만들어 포트를 5000번으로 열어주고, 프론트 서버를 만들어 포트를 3000번으로 열어주면 둘은 출처가 달라져 버리니까.

이런 이유들로 만들어진 SOP의 예외 조항 중 하나가 바로 CORS다.

"Generally, reading information from another origin is forbidden. However, an origin is permitted to use some kinds of resources retrieved from other origins. For example, an origin is permitted to execute script, render images, and apply style sheets from any origin. Likewise, an origin can display content from another origin, such as an HTML document in an HTML frame. Network resources can also opt into letting other origins read their information, for example, using Cross-Origin Resource Sharing." - RFC 6454 - 3.4.2 Network Access

이미지 출처

참고로 출처 비교 로직은 서버가 아니라 브라우저에 구현되어 있다. 따라서 CORS 정책을 위반하더라도 서버 간 응답과 요청은 정상적으로 작동한다. 정책을 어길 시에는 브라우저가 서버의 응답을 파기할 뿐이다.

 

때문에, 다른 Origin의 데이터를 읽고 싶으면 cors표준을 지켜서 내 사이트로부터의 응답에 "다른 Origin도 허용해줘"라고 말하면 된다

 

2. 백엔드 서버(Flask)에서의 CORS 설정 방법은?

백엔드 서버에서 API의 응답 헤더를 변경해준다. 

 

허용할 Origin을 Access-Control-Allow-Origin 응답 헤더에 넣어주면된다. 그러면 다른 Origin이라도 json 데이터와 같은 자원들을 읽을 수 있다.

 

  • 모든 사이트를 허용하는 경우 : "Access-Control-Allow-Origin": *
  • 특정 사이트만 허용하는 경우 : "Access-Control-Allow-Origin": 특정사이트
import boto3
from flask import Flask, render_template, request, jsonify, Response
from flask_cors import CORS
import os

application = Flask(__name__)

cors = CORS(application, resources={r"/fileupload/*": {"origins": "*"}})

@application.route('/')
def main():
    return "핵심 쏙쏙 AWS"

@application.route('/fileupload', methods=['POST'])
def file_upload():
    file = request.files['file']
    s3 = boto3.client('s3',
                      aws_access_key_id=os.environ["AWS_ACCESS_KEY_ID"],
                      aws_secret_access_key=os.environ["AWS_SECRET_ACCESS_KEY"]
                      )
    s3.put_object(
        ACL="public-read",
        Bucket=os.environ["BUCKET_NAME"],
        Body=file,
        Key=file.filename,
        ContentType=file.content_type
    )
    
    res = Response("block")
    res.headers["Access-control-Allow-Origin"] = "*"

    return jsonify({'result': 'success'})

if __name__ == '__main__':
    application.debug = True
    application.run()

 

반응형

'AWS' 카테고리의 다른 글

EC2란?  (0) 2022.03.18

BELATED ARTICLES

more