Skip to content
Merged
Show file tree
Hide file tree
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
279 changes: 279 additions & 0 deletions dhyun2/4.CSRF, 클릭재킹, 오픈 리다이렉트.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# XSS 이외의 대표적인 수동 공격: CSRF, 클릭재킹, 오픈 리다이렉트

웹 애플리케이션을 공격하는 수동적 공격은 사용자가 의도하지 않은 행동을 하도록 유도하는 방식으로, 사용자 신뢰를 기반으로 공격이 수행됩니다. 대표적으로 **CSRF(Cross-Site Request Forgery)**, **클릭재킹(Clickjacking)**, **오픈 리다이렉트(Open Redirect)**가 있으며, 본 문서에서는 각 공격의 구조와 대응 방법을 React 환경에서의 실전 대응 방식까지 포함해 정리합니다.

---

## 1. CSRF (Cross-Site Request Forgery)

### 1.1 개념 및 위협 사례

CSRF는 인증된 사용자의 권한을 도용하여 의도하지 않은 요청을 수행하게 만드는 공격입니다. 피해자가 로그인된 상태에서 악성 웹사이트를 방문할 경우 공격자가 특정 요청을 자동으로 보내어 중요한 작업(예: 송금, 비밀번호 변경 등)을 수행할 수 있습니다.

**실제 위협 사례:**

- 인터넷 뱅킹 사이트에서 로그인된 사용자의 세션을 이용하여 공격자가 공격 페이지에서 송금 요청을 자동 실행.
- 관리자 페이지에서 사용자 삭제, 권한 변경 요청을 악성 이미지 태그로 실행.

### 1.2 구조

1. 사용자가 A 사이트에 로그인하여 세션 쿠키가 브라우저에 저장됨.
2. 공격자가 만든 B 사이트를 사용자가 방문.
3. B 사이트에서 `<img src="https://a.com/transfer?amount=1000">` 같은 요청을 자동으로 보냄.
4. 브라우저는 A 사이트의 쿠키를 자동으로 포함시켜 요청을 보냄.
5. A 사이트는 요청을 인증된 요청으로 오해하고 처리.

---

### 1.3 대응 방법

#### 토큰을 사용하는 CSRF 대책

요청마다 유효한 CSRF 토큰을 함께 전송하게 하여 서버에서 이를 검증함으로써 공격을 방지합니다.

**React 예시:**

```tsx
<form method='POST' action='/api/submit'>
<input type='hidden' name='csrf_token' value={csrfToken} />
<button type='submit'>전송</button>
</form>
```

**이 코드는 무엇을 하나요?**

- `csrf_token`을 숨은 필드로 넣어 서버에 함께 전송함으로써, 요청이 사용자에 의해 의도적으로 발생했는지를 확인합니다.

**서버 예시 (Node.js Express):**

```ts
app.post('/api/submit', (req, res) => {
if (req.body.csrf_token !== req.session.csrf_token) {
return res.status(403).send('CSRF 공격 차단됨');
}
// 유효한 요청 처리
});
```

---

#### Double Submit Cookie 방식

클라이언트에서 CSRF 토큰을 쿠키와 헤더 양쪽에 실어 전송하고, 서버에서 이를 비교하여 일치할 경우에만 요청을 허용합니다.

```ts
document.cookie = 'csrfToken=secureValue';
fetch('/api/update', {
method: 'POST',
headers: {
'X-CSRF-Token': 'secureValue',
},
});
```

**이 방식의 핵심은?**

- 브라우저가 자동으로 쿠키를 전송하지만, 헤더의 값은 명시적으로 클라이언트에서 설정해야 하므로 CSRF 방어가 가능해집니다.

---

#### SameSite 쿠키 설정

서버는 세션 쿠키에 SameSite 속성을 설정하여 외부 사이트로부터의 요청에 대해 쿠키 전송을 차단합니다.

```http
Set-Cookie: sessionid=abc123; SameSite=Strict; Secure
```

- `Strict` 모드는 완벽한 보호를 제공합니다. 외부에서 어떤 요청도 쿠키를 동반하지 않습니다.

---

#### Origin 헤더 검증

POST 요청 시 자동으로 포함되는 `Origin` 헤더를 검증하여 신뢰된 출처인지 확인합니다.

```ts
if (req.headers.origin !== 'https://trust.example.com') {
return res.status(403).send('잘못된 요청 출처');
}
```

- 서버는 `Referer`보다 신뢰성 있는 `Origin` 값을 활용하여 출처를 판단합니다.

---

#### CORS로 보호

CORS 정책을 설정하여, 외부 도메인에서 민감한 API 요청이 불가능하도록 설정합니다.

```ts
res.setHeader('Access-Control-Allow-Origin', 'https://trust.example.com');
res.setHeader('Access-Control-Allow-Credentials', 'true');
```

---

## 2. 클릭재킹 (Clickjacking)

### 2.1 개념 및 위협 사례

Clickjacking은 공격자가 보이지 않거나 투명한 iframe을 이용해 사용자가 클릭을 유도하여, 의도하지 않은 행위(예: 구매 확정, 권한 변경)를 하도록 만드는 UI 기반 공격입니다.

**실제 위협 사례:**

- Facebook 좋아요 버튼을 투명하게 만들어 사용자가 클릭하도록 유도
- 쇼핑몰의 ‘구매’ 버튼을 숨겨 사용자 클릭을 유도

### 2.2 구조

1. 공격자는 `iframe`을 사용해 희생자 사이트를 자신의 페이지에 삽입
2. 투명도 조절 및 위치 조작으로 실제 UI를 보이지 않게 숨김
3. 사용자가 클릭한 버튼이 실제로는 희생자 사이트의 버튼임

---

### 2.3 대응 방법

#### X-Frame-Options 헤더 설정

```http
X-Frame-Options: DENY
```

또는

```http
X-Frame-Options: SAMEORIGIN
```

- 해당 설정은 웹 페이지가 어떤 `iframe`에도 삽입되지 않도록 방지합니다.

---

#### CSP frame-ancestors 설정

```http
Content-Security-Policy: frame-ancestors 'self';
```

- CSP 방식으로도 frame 삽입을 세밀하게 제어할 수 있으며, 향후 `X-Frame-Options`보다 더 권장됩니다.

---

#### JavaScript로 iframe 감지 후 탈출

```tsx
useEffect(() => {
if (window.top !== window.self) {
window.top.location = window.self.location;
}
}, []);
```

- 이 코드는 현재 문서가 프레임 안에 포함되어 있을 경우, 최상위 창으로 페이지를 탈출시킵니다.

---

#### React 컴포넌트 보호 예시

```tsx
const ClickSafeFrame = () => {
useEffect(() => {
if (window.top !== window.self) {
window.top.location = window.location;
}
}, []);

return <div>안전한 콘텐츠</div>;
};
```

- React에서 클릭재킹을 방지하는 일종의 보호 껍데기 컴포넌트입니다.

---

## 3. 오픈 리다이렉트 (Open Redirect)

### 3.1 개념 및 위협 사례

오픈 리다이렉트는 신뢰된 도메인을 이용하여 공격자가 외부 악성 사이트로 사용자를 리디렉션시키는 공격입니다. 피싱, 인증정보 탈취, 쿠키 탈취 등으로 이어질 수 있습니다.

**실제 위협 사례:**

- 이메일에 포함된 링크가 `https://secure.bank.com/login?next=https://evil.com/phishing` 처럼 보이며, 사용자는 `secure.bank.com`을 믿고 클릭
- 로그인 후 리다이렉트 주소를 조작하여 악성 코드가 포함된 페이지로 유도

### 3.2 구조

1. 신뢰할 수 있는 도메인에서 외부 주소로 리디렉션을 허용하는 구조
2. 사용자는 신뢰된 도메인을 클릭하나 결과적으로 악성 사이트로 이동
3. 공격자는 인증 정보를 탈취하거나 브라우저에 악성 코드를 주입

---

### 3.3 대응 방법

#### 리다이렉트 주소 화이트리스트 검증

```ts
const whitelist = ['example.com', 'secure.example.com'];
const redirectUrl = new URL(req.query.url);

if (!whitelist.includes(redirectUrl.hostname)) {
return res.status(400).send('불허된 리다이렉션');
}

res.redirect(redirectUrl.href);
```

- 사용자가 입력한 URL이 신뢰된 도메인에 속하는지 검증합니다.

---

#### 내부 경로만 허용

```ts
const safePaths = ['/home', '/profile', '/dashboard'];
const path = req.query.path;

if (!safePaths.includes(path)) {
return res.redirect('/home');
}

res.redirect(path);
```

- 외부 주소가 아닌 내부 URI 경로만 허용함으로써 위험을 원천 차단합니다.

---

#### React Router에서의 방어적 처리

```tsx
import { useNavigate } from 'react-router-dom';

const RedirectPage = () => {
const navigate = useNavigate();

const redirectSafe = (target: string) => {
const whitelist = ['/home', '/about'];
if (whitelist.includes(target)) {
navigate(target);
} else {
navigate('/home');
}
};

useEffect(() => {
const url = new URLSearchParams(window.location.search).get('to');
redirectSafe(url || '/home');
}, []);

return <p>Redirecting...</p>;
};
```

- 사용자가 URL 파라미터로 입력한 경로를 신뢰 가능한 경로로 제한하며, 그렇지 않으면 홈으로 이동시킵니다.

---
82 changes: 82 additions & 0 deletions dhyun2/5.인증, 인가.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# 인증과 인가: 로그인 정보 보호와 스토리지 사용 시 주의사항

웹 애플리케이션에서 인증(Authentication)과 인가(Authorization)는 사용자의 신원을 확인하고, 해당 사용자가 어떤 리소스에 접근할 수 있는지를 결정하는 중요한 보안 단계입니다. 이 과정에서 사용자 정보를 안전하게 다루기 위해서는 다양한 브라우저 저장 방식과 그에 따른 보안 설정을 정확히 이해하고 활용해야 합니다.

---

## 1. 로그인 정보 유출에 주의하기

### 1.1 HTTPS를 통해 안전한 통신 보장

- 로그인 정보(세션 쿠키 등)는 반드시 HTTPS를 통해 암호화된 채널에서 전송되어야 하며, TLS를 강제하는 방식으로 설정해야 합니다.
- HTTP로 접속했을 경우 HTTPS로 리디렉션하거나 접근 자체를 차단하는 보안 설정이 필요합니다.

### 1.2 Secure 속성

- `Secure` 속성이 설정된 쿠키는 HTTPS 연결이 아닌 경우 브라우저가 서버에 전송하지 않습니다.

```http
Set-Cookie: sessionid=abc123; Secure
```

### 1.3 HttpOnly 속성

- `HttpOnly` 속성을 통해 JavaScript에서 쿠키에 접근하는 것을 차단할 수 있으며, XSS로 인한 쿠키 탈취를 방지합니다.

```http
Set-Cookie: sessionid=abc123; HttpOnly
```

---

## 2. 브라우저의 저장소 사용 시 보안 고려사항

웹 애플리케이션은 로그인 정보 또는 토큰을 저장하기 위해 쿠키 외에도 `localStorage`, `sessionStorage`, `IndexedDB` 등을 사용할 수 있습니다. 그러나 각각 보안 특성이 다르므로 주의가 필요합니다.

### 2.1 localStorage / sessionStorage 사용 시 주의점

| 항목 | 설명 |
| --------- | ----------------------------------------------------------------------------- |
| 접근 방식 | JavaScript를 통해 직접 접근 가능 |
| 지속성 | localStorage는 브라우저 종료 후에도 유지, sessionStorage는 탭이 닫히면 제거됨 |
| 보안 위험 | XSS 공격에 취약하여 토큰이 탈취될 수 있음 |
| 사용 제한 | 민감한 정보(액세스 토큰 등)는 가급적 저장하지 않는 것이 권장됨 |

**예시 (취약):**

```js
// XSS에 의해 탈취될 수 있음
localStorage.setItem('access_token', token);
```

### 2.2 안전하게 스토리지 사용하기

- 민감한 정보는 가급적 브라우저 저장소가 아닌 쿠키(HttpOnly + Secure)로 저장
- 꼭 localStorage를 사용해야 하는 경우, XSS 방지를 위해 콘텐츠 보안 정책(CSP)을 강력히 적용

### 2.3 세션 쿠키 기반 인증

- 로그인 세션은 서버 측 세션과 연동되는 쿠키에 저장하고, 이 쿠키에 `Secure`, `HttpOnly`, `SameSite` 설정을 함께 적용하여 보안을 강화할 수 있습니다.

```http
Set-Cookie: sessionid=xyz789; Secure; HttpOnly; SameSite=Strict
```

---

## 3. 정리

| 저장 방식 | XSS에 안전한가? | 지속성 | 서버 자동 전송 여부 | 추천 용도 |
| ----------------- | --------------- | ------------------------- | ------------------- | ------------------ |
| `HttpOnly Cookie` | ✅ | 브라우저 설정에 따라 | ✅ | 로그인 세션 유지 |
| `localStorage` | ❌ | 브라우저 종료 후에도 유지 | ❌ | 비민감한 UI 설정 |
| `sessionStorage` | ❌ | 탭이 닫히면 삭제 | ❌ | 비민감한 단기 정보 |

---

## 4. 권장 보안 조치 요약

- **세션 관리**: `Secure`, `HttpOnly`, `SameSite` 속성을 갖는 쿠키를 기본값으로 설정
- **스토리지 사용 제한**: localStorage는 가급적 사용하지 않으며, 사용할 경우 CSP 및 XSS 필터 적용
- **HTTPS 강제**: 인증 과정 및 API 요청은 반드시 HTTPS로 제한
- **XSS 대응**: 모든 사용자 입력값에 대해 escaping 및 sanitization 적용