Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 254 additions & 0 deletions dhyun2/3. Origin에 대한 애플리케이션 간 접근 제한.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# Origin과 애플리케이션 간 접근 제한

잘못된 접근 막기 위한 same origin policy의 구조 알아보고, 동일 출처 정책에도 불구하고 외부 사이트로 접근하기 위한 CORS(cross origin resource sharing)을 살펴본다.
이어서 동일 출처 정책의 보호 범위를 넘어선 사이드 채널 공격과 쿠키의 전송을 학습한다. 이후 http서버에 cors설정을 추가하는 내용으로 진행한다.

## 1 애플리케이션간 접근 제한의 필요성

iframe을 사용해 로그인 페이지를 삽입한 피싱 사이트가 있으면 접속 제한이 전혀 없는 브라우저를 사용하고 있다면, 사이트는 iframe을 통해 훔쳐 볼 수 있음

```html
<!-- 악의적인 피싱 사이트의 코드 예시 -->
<iframe
src="https://legitimate-bank.com/login"
id="loginFrame"
style="opacity: 0.01"
></iframe>
<div class="fake-login-form" style="position: absolute; top: 0; left: 0;">
<form onsubmit="stealCredentials(event)">
<input type="text" placeholder="사용자 ID" />
<input type="password" placeholder="비밀번호" />
<button type="submit">로그인</button>
</form>
</div>
```

개인정보 다루는 웹 앱 개발자는 외부에서 잘못된 방법으로 접속할 수 없게 항상 주의해야 함

## 2. 동일 출처 정책에 의한 보호

인터넷 리소스 공개할 때 다른 웹 앱에서 접속을 반드시 제한해야함. 동일 출처 정책은 브라우저 내장된 접근 제한 방식을 말함. 웹 앱 사이에서 출처라는 경계를 설정해 서로의 접근을 제한하는 것이다.

### 2.1 출처는 보통 스키마명(프로토콜), 호스트명, 포트번호의 구조를 가짐

https://example.com:443/path/to/index.html
의 출처는 https://example.com:443이 된다.

웹 앱 출처가 같으면 동일 출처 다르면 교차 출처라고 한다.

스키마명, 호스트명, 포트번호 중 하나만 달라도 교차 출처가 된다.(기본 포트는 80으로 생략 가능)

### 2.2 동일 출처 정책

일정한 조건에 따라 교차 출처 리소스에 접근을 제한 하는 방식을 동일 출처 정책이라 한다. 브라우저는 기본이 동일 출처 정책으로 설정되어있음.

대표적으로 다음과 같은것들을 접근 제한함:

- 자바스크립트를 사용해 교차 출처로 요청 전송
- 자바 스크립트를 사용해 iframe 내 교차 출처 페이지에 접근
- 교차 출처의 이미지를 불러오는 <canvas>요소의 데이터에 접근
- web storage와 indexedDB에 저장된 교차 출처 데이터에 접근

### 2.2.1 자바스크립트 사용해 교차 출처로 요청 전송 제한

동일 출처 정책은 fetch 함수와 XMLHttpRequest를 사용해 교차 출처에 요청 전송을 제한한다.

```javascript
// 예시: https://example.org에서 다른 출처로 요청
try {
const response = await fetch('https://different-origin.com/api/data');
const data = await response.json();
} catch (error) {
console.error('교차 출처 요청이 차단됨:', error);
}
```

### 2.2.2 자바스크립트를 사용해 iframe의 페이지에 접근 제한

postMessage 함수가 교차 출처에서도 안전한 이유:

1. 메시지 출처 검증: event.origin으로 발신자 검증 가능
2. 구조화된 데이터: DOM 직접 접근이 아닌 메시지 기반 통신
3. 명시적 수신 처리: 수신측에서 메시지 핸들러를 통한 제어
4. 양방향 통신 보장: 응답 메시지도 동일한 보안 체계 적용
5. 격리된 실행 컨텍스트: 각 프레임의 독립성 보장

### 2.2.3 Canvas 요소 데이터에 접근 제한

이미지를 가공할 때 편리하지만 교차 출처의 이미지를 불러올 때는 동일 출처 정책에 의해 접근이 제한됨. 교차 출처의 이미지를 canvas로 불러오면 이미 오염된 상태로 간주되어 불러오기 실패함. 제한 완화하려면 CORS로 이미지 파일 불러와야 함.

### 2.2.4 WebStorage와 indexedDB에 저장된 교차 출처 데이터에 접근 제한

브라우저 내장된 데이터 저장 기능으로서 web storage, indexedDB 등이 있는데 여기에 저장된 데이터도 동일 출처 정책에 따라 접근이 제한됨. 세션스토리지는 출처뿐 아니라 새로운 탭과 윈도우 간의 접근도 제한함.

예시:

```javascript
// 탭 A (https://example.com)
sessionStorage.setItem('userToken', 'abc123');

// 탭 B (https://example.com - 새 탭)
console.log(sessionStorage.getItem('userToken')); // null

// 탭 C (https://different-origin.com)
console.log(localStorage.getItem('userToken')); // null
```

### 2.3 동일 출처에 의해 접근 제한되지 않는 사례

각 요소별 제한이 없는 상세 이유:

| 요소 | 제한이 없는 이유 | 보안 고려사항 | 실제 사용 예시 |
| ---------- | ------------------------------------------------------------- | -------------------------------------------- | --------------------------- |
| `<script>` | - 웹의 기본 동작<br>- CDN 활용 필수<br>- 공개 라이브러리 사용 | - integrity 속성으로 검증<br>- CSP 설정 필요 | jQuery, React 등 라이브러리 |
| `<link>` | - CSS는 표시 전용<br>- 스크립트 실행 불가 | - @import 규칙 주의<br>- CSP 설정 | Bootstrap, 폰트 스타일 |
| `<img>` | - 픽셀 데이터만 표시<br>- 원본 접근 불가 | - Canvas 사용 시 주의<br>- alt 속성 필수 | CDN 이미지, 프로필 사진 |
| `<form>` | - 새 컨텍스트로 전환<br>- 응답이 새 페이지 | - CSRF 토큰 필수<br>- SameSite 쿠키 | 로그인, 결제 폼 |

## 3. CORS (Cross-Origin Resource Sharing)

동일 출처 정책 제한을 피해 교차 출처로 접근할 수 있는 방법은 무엇일까? 출처를 통해 네트워크에 접근하는 출처 간 리소스 공유(CORS)의 구조를 알아보자.

### 3.1 CORS 방식

XML과 fetch 함수를 사용해 교차 출처로 요청을 전송하는 것은 동일 출처 정책에 따라 금지되어 있다.
그러나 응답에 포함된 HTTP 헤더에 접속해도 좋다는 허가가 주어진 리소스는 접근이 가능하다. 이때 HTTP 헤더를 CORS 헤더라고 한다. CORS 헤더에는 접근을 허락하는 출처의 조건이 기재되어 있다.

### 3.2 단순 요청

GET 또는 POST로 전송하는 브라우저의 기본 요청을 단순 요청이라고 한다. 구체적으로 CORS의 스펙에 기재된 fetch standard에서 CORS-safelisted로 간주되는 HTTP 메서드와 HTTP 헤더만을 전송하는 요청을 의미한다.

CORS-safelisted로 정의된 HTTP 메서드와 HTTP 헤더는 다음과 같다:

| 구분 | 허용되는 값 |
| ------------ | ------------------------------------------------------------------ |
| HTTP Method | GET, HEAD, POST |
| HTTP Headers | Accept, Accept-Language, Content-Language |
| Content-Type | application/x-www-form-urlencoded, multipart/form-data, text/plain |

Access-Control-Allow-Origin: \* 사용의 장단점:

| 구분 | 내용 |
| ---- | -------------------------------------------------------------------------------------------------------------------- |
| 장점 | - 구현 간편성<br>- 모든 클라이언트 접근 가능<br>- 설정 단순화<br>- 개발 환경에서 빠른 테스트 |
| 단점 | - 보안 위험 증가<br>- 인증된 요청 불가<br>- 무차별 접근 허용<br>- credentials 옵션 사용 불가<br>- 잠재적 보안 취약점 |

### 3.3 Preflight Request

Preflight Request가 필요한 상세 이유:

1. 서버 보호

- 예상치 못한 요청으로 인한 서버 부하 방지
- 리소스 변경 작업의 사전 검증
- 악의적인 요청 차단
- 서버 리소스 보호

2. 보안 강화
- DELETE: 데이터 삭제 위험 방지
- PUT: 데이터 수정 위험 방지
- 커스텀 헤더: 비표준 동작 검증
- 복잡한 요청에 대한 사전 승인

Preflight 요청/응답 예시:

```http
# Preflight 요청
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, X-Custom-Header

# Preflight 응답
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT, POST, GET, DELETE
Access-Control-Allow-Headers: Content-Type, X-Custom-Header
Access-Control-Max-Age: 86400
```

### 3.4 쿠키를 포함하는 요청 전송

credentials 옵션 상세:

| 옵션값 | 동작 | 옵션 없을 때의 동작 | 사용 사례 |
| ----------- | --------------------- | ------------------- | ---------------------------- |
| same-origin | 동일 출처만 쿠키 전송 | 기본값으로 동작 | 일반적인 API 요청 |
| include | 모든 요청에 쿠키 포함 | 쿠키 미포함 | 인증이 필요한 교차 출처 요청 |
| omit | 쿠키 전송 안 함 | 동일 출처도 미포함 | 공개 API 요청 |

### 3.5 crossorigin 속성을 사용하는 CORS 요청

CORS 모드로 요청하는 주요 이유와 사례:

1. 에러 추적 향상

```html
<script
src="https://cdn.example.com/app.js"
crossorigin="anonymous"
onerror="handleError(event)"
></script>
```

- 상세한 에러 정보 수집 가능
- 스택 트레이스 확인
- 디버깅 용이성 증가

2. 폰트 리소스 처리
```css
@font-face {
font-family: 'CustomFont';
src: url('https://fonts.example.com/font.woff2') format('woff2');
}
```
- 브라우저 폰트 캐싱
- CORS 정책 준수
- 리소스 최적화

## 4. PostMessage를 사용한 iframe 통신

현업에서의 주요 활용 사례:

1. 마이크로프론트엔드 통신

```javascript
// 메인 앱
const microFrontend = document.querySelector('#micro-frontend');
microFrontend.contentWindow.postMessage(
{
type: 'INIT_DATA',
payload: { user: currentUser },
},
'https://micro.example.com'
);
```

2. 결제 시스템 연동

```javascript
// 결제 모듈
window.addEventListener('message', (event) => {
if (event.origin !== 'https://payment.example.com') return;
if (event.data.type === 'PAYMENT_COMPLETE') {
processPayment(event.data.payload);
}
});
```

3. 소셜 로그인

```javascript
// OAuth 팝업과 통신
window.addEventListener('message', (event) => {
if (event.origin !== 'https://oauth-provider.com') return;
if (event.data.type === 'AUTH_SUCCESS') {
handleLogin(event.data.token);
}
});
```

## 결론

웹 애플리케이션의 보안은 Origin 기반의 접근 제한에 크게 의존한다. Same-Origin Policy는 기본적인 보안을 제공하고, CORS는 필요한 교차 출처 통신을 안전하게 구현할 수 있게 한다. 개발자는 이러한 메커니즘을 이해하고 적절히 구현하여 안전한 웹 애플리케이션을 개발해야 한다.