CORS 문제 해결: 크로스 도메인 요청과 보안 고려사항
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
웹 개발에서 클라이언트와 서버 간의 크로스 도메인 요청은 일반적이지만, 보안상의 이유로 브라우저는 기본적으로 이러한 요청을 차단합니다. 이를 해결하기 위해 CORS(Cross-Origin Resource Sharing)가 도입되었습니다. CORS는 웹 애플리케이션이 다른 도메인에서 리소스를 요청할 수 있도록 허용하는 메커니즘입니다. 이 글에서는 CORS 문제의 원인과 해결 방법, 그리고 크로스 도메인 요청 시의 보안 고려사항을 다루겠습니다.
CORS란 무엇인가?
CORS는 브라우저에서 실행되는 웹 애플리케이션이 다른 도메인, 프로토콜 또는 포트에서 리소스를 요청할 때 발생하는 보안 정책입니다. 웹 표준에서, 동일 출처 정책(Same-Origin Policy)은 다른 출처의 리소스에 대한 액세스를 제한하여 보안을 강화합니다. 그러나 API 호출이나 리소스 공유가 필요할 때, CORS 헤더를 사용하여 이러한 제한을 해제할 수 있습니다.
주요 CORS 헤더
- Access-Control-Allow-Origin: 요청을 허용할 출처(origin)를 지정합니다.
*
로 모든 출처를 허용할 수도 있지만, 이는 보안상 위험할 수 있습니다. - Access-Control-Allow-Methods: 허용할 HTTP 메서드(GET, POST, PUT 등)를 지정합니다.
- Access-Control-Allow-Headers: 클라이언트가 요청에 사용할 수 있는 HTTP 헤더를 지정합니다.
- Access-Control-Allow-Credentials: 자격 증명(쿠키, HTTP 인증)을 포함한 요청을 허용할지 여부를 지정합니다.
CORS 문제의 원인
1. 브라우저 보안 정책
브라우저는 클라이언트와 서버 간의 동일 출처 정책을 적용하여, 악의적인 사이트가 사용자의 데이터를 탈취하는 것을 방지합니다. 다른 출처의 리소스를 요청하면 기본적으로 CORS 오류가 발생합니다.
2. 서버 구성 문제
서버에서 CORS 헤더를 올바르게 설정하지 않으면, 브라우저가 클라이언트의 요청을 차단할 수 있습니다. 서버에서 허용할 도메인, 메서드, 헤더를 명확하게 설정해야 합니다.
3. 프리플라이트 요청(Preflight Request)
브라우저는 실제 요청을 보내기 전에, OPTIONS
메서드를 사용하여 서버에 미리 확인 요청을 보내는 프리플라이트 요청을 수행합니다. 이는 클라이언트가 보내려는 요청이 허용되는지 확인하기 위함입니다. 서버가 프리플라이트 요청에 적절하게 응답하지 않으면 CORS 오류가 발생할 수 있습니다.
CORS 문제 해결 방법
1. 서버에서 CORS 헤더 설정
서버에서 Access-Control-Allow-Origin
헤더를 적절히 설정하여, 특정 출처 또는 모든 출처의 요청을 허용할 수 있습니다. 예를 들어, Node.js의 Express 프레임워크를 사용하는 경우 다음과 같이 설정할 수 있습니다:
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
2. 프리플라이트 요청 처리
서버는 프리플라이트 요청(OPTIONS
메서드)에 대해 올바르게 응답해야 합니다. 이 응답에는 허용할 메서드, 헤더, 자격 증명 등의 정보가 포함되어야 합니다.
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.sendStatus(200);
});
3. 자격 증명 포함 요청
쿠키나 HTTP 인증 정보를 포함한 요청의 경우, 서버에서 Access-Control-Allow-Credentials
헤더를 true
로 설정해야 합니다. 클라이언트 측에서는 withCredentials
옵션을 설정해야 합니다.
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
클라이언트 코드:
axios.get('https://example.com/data', { withCredentials: true })
.then(response => console.log(response.data));
4. 프록시 서버 사용
클라이언트와 서버 사이에 프록시 서버를 두어 CORS 문제를 우회할 수 있습니다. 이 방법은 특히 프런트엔드 개발 중에 유용할 수 있습니다. 예를 들어, 개발 중에는 로컬에서 프록시를 사용하여 CORS 문제를 피하고, 실제 배포 시 서버에서 CORS를 적절히 처리할 수 있습니다.
5. 클라이언트 측 조치
서버에서 CORS를 올바르게 설정하지 못한 경우, 클라이언트 측에서는 JSONP(JSON with Padding)와 같은 기술을 사용할 수 있습니다. 하지만 이 방법은 제한적이며, 기본적으로 GET 요청에서만 사용할 수 있습니다.
CORS 보안 고려사항
1. 정확한 출처 설정
Access-Control-Allow-Origin
을 *
로 설정하여 모든 출처를 허용하면 보안 위험이 증가합니다. 가능하다면, 신뢰할 수 있는 특정 도메인만 허용하는 것이 좋습니다.
2. 자격 증명 보호
Access-Control-Allow-Credentials
를 true
로 설정할 때는, 반드시 특정 출처만 허용해야 합니다. 그렇지 않으면 크로스 도메인 공격에 취약해질 수 있습니다.
3. 보안 감사
CORS 설정을 주기적으로 검토하고, 보안 결함이 발생하지 않도록 주의합니다. 특히, API를 공용으로 제공하는 경우 더욱 철저한 보안 검토가 필요합니다.
4. 헤더와 메서드 제한
허용할 헤더와 메서드를 최소화하여, 공격의 표면적을 줄이는 것이 좋습니다. 예를 들어, 클라이언트가 실제로 필요로 하지 않는 메서드나 헤더를 허용하지 않는 것이 안전합니다.
결론
CORS 문제는 크로스 도메인 요청을 허용하면서도 웹 애플리케이션의 보안을 유지하기 위해 필수적인 고려사항입니다. 서버에서 올바른 CORS 헤더를 설정하고, 프리플라이트 요청을 처리하며, 자격 증명 요청을 적절히 관리하는 것이 중요합니다. 또한, 보안 측면에서도 신중한 접근이 필요하며, 이를 통해 안전하고 확장 가능한 웹 애플리케이션을 구축할 수 있습니다. CORS를 적절히 이해하고 처리하면, 사용자 경험을 향상시키면서도 보안을 유지할 수 있는 웹 애플리케이션을 개발할 수 있습니다.
- 공유 링크 만들기
- X
- 이메일
- 기타 앱