CORS(Cross-Origin Resource Sharing, 교차 출처 리소스 공유)는 HTTP 헤더를 사용하여 각기 다른 출처의 웹 어플리케이션에 접근 권한을 부여하는 것을 뜻합니다.
Origin(출처)은 도메인 및 스키마, 포트 등을 가리키며, 클라우드타입에서 배포하는 서비스를 사용하는 경우에도 각 프레임워크 및 라이브러리에서 권장하는 CORS 설정을 적용해야 합니다.
예를 들어, 프론트엔드 측 https://frontend.com
에서 백엔드 측 https://backend.com
에 데이터를 요청하는 경우 CORS를 기반으로 하여 HTTP 요청을 하게 되는데, 적절한 설정이 되어있지 않은 경우 코드상 문제가 없다고 하더라도 HTTP 에러가 발생할 수 있습니다.
더불어 보안 측면에서도 허용되지 않은 출처의 서비스가 악의적인 목적으로 데이터를 요청하고 응답받는 등의 사고가 발생할 수 있기 때문에 CORS 관련 설정을 해주는 것이 좋습니다.
프레임워크별 CORS 적용
Node.js(Express)
Express를 통해 구현된 웹 서버의 경우 CORS 설정을 위해서 cors 라는 별도의 npm 패키지 설치가 필요합니다. 적용을 위한 코드의 예시는 다음과 같습니다.
var express = require('express')var cors = require('cors')var app = express()var corsOptions = {origin: 'https://sub.example.app',// 이 설정은 https://sub.example.app 인 origin을 허용합니다.// 어플리케이션 구성에 맞게 origin 규칙을 적용해주세요.optionsSuccessStatus: 200}app.get('/users/:id', cors(corsOptions), function (req, res, next) {res.json({msg: 'https://sub.example.app 규칙인 Origin에 대하여 개방'})})app.listen(80, function () {console.log('80번 포트로 서비스 하는 웹서버에 CORS 적용')})자세한 설정은 다음 링크를 참고해주세요.
Nest.js
Nest.js의 경우
app
객체 생성시 CORS 관련 설정을 적용할 수 있습니다.const app = await NestFactory.create(AppModule);app.enableCors();await app.listen(3000);CORS 적용 시 다음과 같이 모듈의 설정에 규칙을 추가할 수 있습니다.
AppModule.forRoot({cors: {origin: 'https://sub.example.app',// 이 설정은 https://sub.example.app 인 origin을 허용합니다.// 어플리케이션 구성에 맞게 origin 규칙을 구체적으로 적용해주세요.credentials: true,},}),자세한 설정은 다음 링크를 참고해주세요.
Spring Boot
Spring Boot에서 CORS를 적용하는 방법은 크게 컨트롤러/전역 레벨 두 가지로 나뉘며, 구성 및 상황에 맞게 적용해주세요.
자세한 설정은 다음 링크를 참고해주세요.
컨트롤러 CORS 적용
어노테이션을 통해 컨트롤러 전체 메서드 혹은 일부 메서드에 한정하여 CORS 설정을 적용할 수 있습니다.
컨트롤러 전체 메서드
@CrossOrigin(origins = "https://sub.example.app")// 이 설정은 https://sub.example.app 인 origin을 허용합니다.@RestController@RequestMapping("/api/v1/students")public class StudentController {@Autowiredprivate StudentRepository studentRepository;@GetMappingpublic List<Student> getAllStudents() {return studentRepository.findAll();}@PostMappingpublic Student createStudent(@RequestBody Student student) {try {return studentRepository.save(student);} catch (Exception e) {System.out.println(e.getMessage());return null;}}}특정 메서드
@RestController@RequestMapping("/api/v1/students")public class StudentController {@Autowiredprivate StudentRepository studentRepository;@CrossOrigin(origins = "https://sub.example.app")// 이 설정은 https://sub.example.app 인 origin을 허용합니다.@GetMappingpublic List<Student> getAllStudents() {return studentRepository.findAll();}@PostMappingpublic Student createStudent(@RequestBody Student student) {try {return studentRepository.save(student);} catch (Exception e) {System.out.println(e.getMessage());return null;}}}
전역적 CORS 적용
전역적으로 CORS 설정을 적용하는 경우
WebMvcConfigurer
객체를 Bean으로 등록하는 config 파일을 생성한 후 다음과 같이 작성합니다.@Configurationpublic class CorsConfiguration {@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurerAdapter() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("https://sub.example.app")// 이 설정은 https://sub.example.app 인 origin을 허용합니다.;}};}}
Flask
Flask를 통해 구현된 웹 서버의 경우 CORS 설정을 위해서 flask-cors 라는 별도의 pip 패키지 설치가 필요합니다. 적용을 위한 코드의 예시는 다음과 같습니다.
app = Flask(__name__)cors = CORS(app, resources={r"/api/*": {"origins": "https://sub.example.app"}})# 이 설정은 https://sub.example.app 인 origin을 허용합니다.@app.route("/api/users")def list_users():return "All users have been returned."자세한 설정은 다음 링크를 참고해주세요.
Django
Django를 통해 구현된 웹 서버의 경우 CORS 설정을 위해서 django-cors-headers 라는 별도의 pip 패키지 설치가 필요합니다.
CORS 설정으로 허용된 출처라 하더라도 CSRF 공격에 관해 신뢰할 수 있는 출처까지 적용되지는 않기 때문에 별도의 옵션을 추가해주어야 합니다. 특히 클라우드타입에서 배포한 서비스에 대해서 공개된 도메인이
CSRF_TRUSTED_ORIGINS
에 등록되지 않은 경우 어드민 페이지에 접근이 되지 않는 등의 문제가 발생할 수 있습니다. 적용을 위한 코드의 예시는 다음과 같습니다.settings.py
INSTALLED_APPS = [...,"corsheaders",...,]...MIDDLEWARE = [...,"corsheaders.middleware.CorsMiddleware","django.middleware.common.CommonMiddleware",...,]...# CORS 허용된 출처CORS_ALLOWED_ORIGINS = ["https://example.app","https://sub.example.app","http://localhost:8080","http://127.0.0.1:9000",]...# CSRF 신뢰할 수 있는 출처CSRF_TRUSTED_ORIGINS = ["https://*.example.app",]자세한 설정은 다음 링크를 참고해주세요.