CORS (Cross-Origin Resource Sharing)
- CORS는 원래 브라우저가 서버의 데이터를 보호하기 위해 존재하는 정책입니다. 브라우저는 기본적으로 출처(Origin)가 다른 요청을 차단하여, 악의적인 웹사이트가 임의로 API를 호출하는 것을 막음.
- Same-Origin Policy (SOP, 동일 출처 정책) : 브라우저는 현재 열려 있는 HTML 파일이 실행된 **출처(origin)**와 다른 출처에서 파일을 직접 가져오는 것을 제한합니다.
- 출처(Origin)는 프로토콜 + 도메인 + 포트번호로 구성됩니다.
- 보안 위협 예시: CORS가 없다면?
- 1. 사용자가 https://bank.com에 로그인 (쿠키가 자동 포함됨)
- 2. 사용자가 악성 사이트(https://hacker.com)를 방문
- 3. https://hacker.com에서 fetch("https://bank.com/transfer?to=hacker&amount=10000") 실행
- 4. CORS가 없으면 요청이 실행되며, 사용자의 계좌에서 돈이 빠져나감
- 브라우저가 출처(Origin)를 비교하는 방법
- 브라우저는 fetch() 요청을 보낼 때, 현재 페이지의 **출처(Origin)**와 **요청 대상의 출처(Origin)**를 비교합니다
console.log(window.location.origin); // 현재 웹사이트의 출처 확인
window.location.origin = "https://frontend.com"
fetch("https://api.example.com/data")
- 정적 파일(HTML, CSS, JS)을 받은 frontend.com과 fetch() 요청의 대상(api.example.com)의 "출처(Origin)"이 다르면, 브라우저가 CORS 정책에 따라 차단합니다
- 프론트엔드와 백엔드가 다른 출처(Origin)가 되는 이유
- 1. 웹 서버와 앱 서버를 분리해서 운영하는 경우 (도메인 다름)
- 프론트엔드: https://frontend.com
- 백엔드(API 서버): https://api.example.com
- 2. 개발 환경에서 포트가 다르게 설정된 경우 (포트 다름)
- 프론트엔드 (React 개발 서버): http://localhost:3000
- React 프로젝트를 개발할 때, create-react-app 등의 도구를 사용하면 개발용 서버를 실행할 수 있습니다. 이 서버는 정적 파일(HTML, CSS, JS)을 제공하고, 코드 변경을 실시간 반영하는 Hot Reloading 기능을 지원합니다.
- 백엔드 (Spring Boot, Express 서버): http://localhost:8080
- 3. HTTP와 HTTPS가 다를 때 (프로토콜 다름)
- 프론트엔드: https://example.com
- 백엔드(API 서버): http://example.com
- 4. API 서버가 다른 도메인의 백엔드를 호출하는 경우 (프록시 서버 문제)
- 프론트엔드 → 백엔드 (https://api.example.com) → 외부 API (https://external-api.com)
- 1. 웹 서버와 앱 서버를 분리해서 운영하는 경우 (도메인 다름)
- 해결책 : 서버에서 Access-Control-Allow-Origin 헤더 설정
- 브라우저가 응답 헤더를 검사
- 만약 Access-Control-Allow-Origin이 없으면 브라우저는 요청을 차단 (CORS 오류 발생).
- 하지만 Access-Control-Allow-Origin: https://frontend.com이 포함되어 있으면 요청을 허용하고 응답을 정상 처리.
- 브라우저가 응답 헤더를 검사
@CrossOrigin(origins = "http://localhost:3000") // 특정 출처 허용
@RestController
public class ApiController {
@GetMapping("/api/data")
public ResponseEntity<String> getData() {
return ResponseEntity.ok("CORS 해결됨!");
}
}
CSRF (Cross-Site Request Forgery)
- **CSRF(크로스 사이트 요청 위조)**는 공격자가 사용자의 세션을 악용하여 원치 않는 요청을 서버에 보내도록 유도하는 웹 보안 공격 기법입니다. 즉, 사용자가 자신도 모르게 인증된 상태에서 공격자가 의도한 요청을 실행하게 만드는 공격입니다.
- 공격 시나리오
- 1. 사용자가 example.com에 로그인하여 인증 쿠키가 저장됨. (httpOnly가 아니면 JavaScript로 접근 가능)
- 2. 공격자가 CSRF 공격을 수행하는 **악성 웹사이트(evil.com)**를 운영.
- 3. 사용자가 evil.com을 방문하면, 공격자는 자동으로 example.com으로 특정 요청을 보냄.
- 4. <img src="https://example.com/api/transfer?amount=10000&to=attacker-account" />
- 5. 브라우저는 example.com에 로그인된 상태이므로 자동으로 인증된 쿠키를 포함하여 요청을 보냄.
- 6. 서버는 정상적인 사용자의 요청인 줄 알고 공격자의 계좌로 돈을 송금하는 등의 행동을 수행.
- 즉, 사용자는 example.com에서 아무런 조작을 하지 않았지만, 공격자가 원치 않는 요청을 실행하도록 유도하는 것이 CSRF의 핵심.
- CORS가 CSRF 공격을 방어할 수 있을까?
- CORS는 브라우저가 "다른 출처(Origin)"에서 JavaScript로 API를 호출하는 것을 차단하는 보안 정책입니다. 반면, CSRF는 브라우저의 "자동 쿠키 포함" 기능을 악용하는 공격이므로 CORS와 관계없이 발생할 수 있습니다. 즉, CORS는 fetch()나 XMLHttpRequest 같은 JavaScript 요청을 차단하지만, CSRF는 img, form 같은 HTML 요소를 이용하므로 차단되지 않습니다.
- 해결책
- 1. CSRF Token 사용 (가장 일반적인 방법)
- CSRF 토큰은 서버가 요청할 때마다 생성하는 임의의 값으로, 클라이언트가 요청 시 함께 전송해야 함. 브라우저는 자동으로 CSRF 토큰을 포함할 수 없으므로, CSRF 공격이 방지됨.
- 일반적으로 클라이언트는 GET /csrf-token을 먼저 호출하여 토큰을 받아온 후, API 요청에 X-CSRF-Token을 포함하여 전송함.
- 그렇다면, 공격자가 CSRF 토큰 요청을 포함하는 HTML 태그를 추가할 수 있을까?
- 공격자가 HTML 태그(<img>, <script>, <form> 등)를 이용해 CSRF 토큰을 요청할 수는 있지만, 해당 값을 활용하려면 JavaScript가 필요함. 그러나 JavaScript가 CORS 정책(Same-Origin Policy)에 의해 다른 출처의 응답을 읽을 수 없으므로, 공격자가 CSRF 토큰을 알아낼 수 없음.
- CSRF 토큰은 서버가 요청할 때마다 생성하는 임의의 값으로, 클라이언트가 요청 시 함께 전송해야 함. 브라우저는 자동으로 CSRF 토큰을 포함할 수 없으므로, CSRF 공격이 방지됨.
- 2. SameSite Cookie 설정
- 3. Referrer 검증
- 4. CORS(Cross-Origin Resource Sharing) 정책 강화
- 1. CSRF Token 사용 (가장 일반적인 방법)
'개발기술 > 보안' 카테고리의 다른 글
JWT Refresh Token Strategy (0) | 2025.03.07 |
---|---|
네트워크 접근제어(NAC) ; NAT, 방화벽 (0) | 2025.02.25 |
보안의 개념과 기술 (0) | 2025.01.19 |
HTTPS 의 TLS 동작과정 (0) | 2025.01.18 |
Security JWT,세션, 쿠키방식 (0) | 2025.01.15 |