웹 애플리케이션 개발에서 보안은 매우 중요한 요소입니다. 특히, 사용자 인증 및 권한 부여와 관련된 부분에서는 더욱 그러합니다. 토큰을 이용한 인증 방식은 최근 많이 사용되는 방법 중 하나인데, 이 토큰을 어떻게 전달하고 저장할 것인가는 중요한 설계 요소입니다. 여기에서는 토큰을 HTTP 헤더와 쿠키에 넣는 방법을 상세히 설명하고, 두 방법의 차이점을 깊이 있게 분석해 보겠습니다.
### HTTP 헤더에 토큰 넣기
#### 1. 개념 및 방법
HTTP 헤더에 토큰을 넣는 방식은 클라이언트가 서버에 요청을 보낼 때, 요청의 헤더 부분에 인증 토큰을 포함하는 방법입니다. 주로 사용되는 헤더는 `Authorization` 헤더입니다. 다음과 같은 형식을 사용합니다:
```
Authorization: Bearer <token>
```
여기서 `Bearer`는 인증 타입을 나타내며, 그 뒤에 토큰 값을 추가합니다.
#### 2. 구현 예시 (JavaScript, Express)
클라이언트 측 (JavaScript):
```javascript
const token = 'your-jwt-token';
fetch('https://api.example.com/secure-endpoint', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
서버 측 (Node.js, Express):
```javascript
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const verifyToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
jwt.verify(token, 'your-secret-key', (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
app.get('/secure-endpoint', verifyToken, (req, res) => {
res.json({ message: 'Secure data' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
```
### 쿠키에 토큰 넣기
#### 1. 개념 및 방법
쿠키를 사용하여 토큰을 저장하고 서버로 전송하는 방법은 웹 브라우저의 쿠키 기능을 활용하는 방식입니다. 쿠키는 클라이언트 측에 저장되며, 같은 도메인에서 발생하는 모든 HTTP 요청에 자동으로 포함됩니다. 쿠키에 저장된 토큰은 서버에서 읽어들여 인증을 수행할 수 있습니다.
쿠키는 HTTP-only 속성을 설정할 수 있어, 클라이언트 측 스크립트가 쿠키에 접근할 수 없도록 보호할 수 있습니다. 또한 `Secure` 속성을 설정하여 HTTPS를 통해서만 쿠키가 전송되도록 할 수 있습니다.
#### 2. 구현 예시 (JavaScript, Express)
클라이언트 측 (JavaScript):
```javascript
// 쿠키 설정
document.cookie = "token=your-jwt-token; Secure; HttpOnly; SameSite=Strict";
// 쿠키 읽기
const getCookie = (name) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
return null;
};
```
서버 측 (Node.js, Express):
```javascript
const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
const verifyToken = (req, res, next) => {
const token = req.cookies.token;
if (!token) return res.sendStatus(401);
jwt.verify(token, 'your-secret-key', (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
};
app.get('/secure-endpoint', verifyToken, (req, res) => {
res.json({ message: 'Secure data' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
```
### 두 방법의 차이점
#### 1. 보안성
- **HTTP 헤더 방식**: 토큰이 매 요청 시 `Authorization` 헤더에 포함되기 때문에 XSS(Cross-Site Scripting) 공격에 노출될 가능성이 상대적으로 적습니다. 이는 클라이언트 측 스크립트가 이 토큰에 접근하지 않기 때문입니다. 그러나, CSRF(Cross-Site Request Forgery) 공격에 취약할 수 있습니다.
- **쿠키 방식**: 쿠키에 `HttpOnly` 속성을 설정하면 클라이언트 측 스크립트가 쿠키에 접근할 수 없으므로 XSS 공격에 대한 방어가 가능합니다. 하지만, 쿠키는 자동으로 모든 요청에 포함되므로 CSRF 공격에 취약합니다. CSRF를 방지하기 위해서는 CSRF 토큰을 사용하거나 `SameSite` 속성을 적절히 설정해야 합니다.
#### 2. 사용 편의성
- **HTTP 헤더 방식**: 클라이언트 측에서 매 요청 시 헤더를 설정해야 합니다. 이는 클라이언트 측 코드가 조금 더 복잡해질 수 있음을 의미합니다. 또한, 브라우저 외의 클라이언트 (예: 모바일 앱)에서의 구현이 간단합니다.
- **쿠키 방식**: 쿠키는 브라우저가 자동으로 관리하므로 클라이언트 측 코드가 간단해집니다. 한 번 설정된 쿠키는 같은 도메인 내 모든 요청에 자동으로 포함되기 때문에 추가적인 설정이 필요 없습니다. 하지만, 브라우저 환경에 종속적이기 때문에 비브라우저 환경 (예: 모바일 앱)에서는 사용이 어려울 수 있습니다.
#### 3. 서버 설정 및 호환성
- **HTTP 헤더 방식**: 대부분의 서버 프레임워크에서 기본적으로 지원됩니다. 또한, CORS(Cross-Origin Resource Sharing) 설정에서 `Authorization` 헤더를 명시적으로 허용해야 할 수 있습니다.
- **쿠키 방식**: 쿠키는 HTTP 프로토콜의 기본 기능으로, 대부분의 서버 프레임워크에서 별도의 설정 없이 사용 가능합니다. 그러나 CORS 설정에서 쿠키를 허용하려면 추가적인 설정 (`credentials: true`)이 필요할 수 있습니다.
### 결론
HTTP 헤더와 쿠키에 토큰을 저장하고 전달하는 방식은 각각 장단점이 있습니다. HTTP 헤더 방식은 보안성이 높고, 비브라우저 환경에서도 쉽게 사용할 수 있지만, 클라이언트 측 코드가 복잡해질 수 있습니다. 쿠키 방식은 사용이 간편하고 브라우저 환경에서 자동으로 관리되지만, CSRF 공격에 취약할 수 있습니다. 따라서, 애플리케이션의 특성과 요구사항에 따라 적절한 방식을 선택하는 것이 중요합니다.
보안성을 최우선으로 고려해야 하는 경우, 각 방식의 취약점을 보완하는 추가적인 보안 조치를 병행하는 것이 좋습니다. 예를 들어, 쿠키 방식에서는 CSRF 토큰을 사용하거나 `SameSite` 속성을 적절히 설정하고, HTTP 헤더 방식에서는 CSRF 방어를 위한 추가적인 조치를 구현할 수 있습니다.
'게으른 개발자의 끄적거림' 카테고리의 다른 글
.exe 파일이란? (0) | 2024.07.04 |
---|---|
윈도우 제어판 프로그램 제거 방법 (0) | 2024.06.27 |
HTTP 헤더란? (header 구조, 구성 요소) (0) | 2024.06.25 |
SSO(Single Sign-On)이란? (feat. Java코드 예제) (0) | 2024.06.24 |
HTTP란? (구조, 동작 방식, 요청 메서드 등) (0) | 2024.06.20 |