Skip to content
Open
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
146 changes: 146 additions & 0 deletions keyword/chapter08/keyword.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
- Spring Security가 무엇인가?

> Spring 기반 애플리케이션 인증, 인가, 취약점 공격 방어를 담당하는 강력하고 커스터마이징이 용이한 프레임워크이다.
>

**[핵심 동작 원리 요약]**

Spring Security는 스프링 MVC 레이어(Controller)로 요청이 도달하기 전, 서블릿 컨테이너 단계에서 Filter들의 사실을 통해 동작한다.

1. 사용자의 HTTP 요청이 들어오면 스프링의 `DeletegatingFilterProxy`가 요청을 가로채 보안 처리를 전담하는 `FilterChainProxy`에게 넘긴다.
2. 여러 개의 보안 필터(`SecurityFilterChain`)가 순서대로 실행된다.
1. `UsernamePasswordAuthenticationFilter` (폼 로그인 인증 처리), `ExceptionTranslationFilter` (보안 예외처리) 등
3. 필터 체인을 무사히 통과한 검증된 요청만 최종적으로 스프링 MVC의 디스패처 서블릿과 Controller에 도달하게 된다.

**[제공하는 주요 기능 및 보안]**

단순히 로그인 구현 외에도 필요한 많은 보안 기능을 추가로 얻을 수 있다.

- **표준 인증 아키텍처**: 세션-쿠키 기반 전통 로그인부터 JWT 기반 인증, 소셜 로그인 등을 유연하게 구현할 수 있는 구조를 제공한다.
- **메서드 레벨 권한 제어**: URL 기반 제어뿐만 아니라, 특정 서비스 레이어의 매서드 위에 어노테이션을 통해 정교하게 인가를 처리할 수 있다.
- **공격 방어**: 웹 취약점 공격인 CSRF(사이트 간 요청 위조) 방어, Session Fixation(세션 고정 공격) 방어, HTTP 보안 헤더 자동 주입 등을 기본적으로 지원한다.

- 인증(Authentication)vs 인가(Authorization)

> **인증**은 “이 사용자가 주장하는 사람이 진짜 맞는지” 신원 확인, **인가**는 인증을 거쳐 “누구인지 확인된 사용자가, 특정 행동을 할 자격이 있는지” 권한 부여
>

**[인증: Authentication]**

시스템이 “이 사용자가 주장하는 사람이 진짜 맞는지” 확인하는 과정으로 시스템을 사용하려는 주체의 신원을 증명하는 것이다.

**<백엔드 구현 방식>**

- 유저가 입력한 아이디와 비밀번호를 DB에 **저장된 값과 비교**한다.
- 서버는 이 사람이 맞다고 판단되면 증명서 역할을 하는 **세션 ID나 JWT 토큰**을 **발급**해준다.
- 이후 유저는 위의 증명서를 매 요청마다 들고와 인증된 사용자임을 밝힌다.

**<실패시 결과>**

- 만약 비밀번호가 틀리거나 유효하지 않은 토큰을 들고 오면 인증 실패
- **HTTP 상태 코드**로는 **`401 Unauthorized`** 에러를 반환

**<인증 코드 예시>**

사용자가 로그인을 요청했을 때 디비의 비밀번호와 일치하는 지 검증하고 JWT 토큰을 발급해주는 과정

```java
// 유저가 보낸 아이디/비번을 검증하는 인증 과정
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword())
);
// 인증이 성공하면 신원 보증서(토큰) 발행
String jwtToken = tokenProvider.createToken(authentication);
```

**[인가:Authorization]**

인증을 거쳐 “누구인지 확인된 사용자가, 특정 행동을 할 자격이 있는지” 검사하는 과정으로 인증된 사용자가 보호된 자원에 접근하거나 수정할 수 있는 등급인지 확인하는 것이다.

**<백엔드 구현 방식>**

- 시스템은 사용자의 정보(역할, 등급 등)을 확인한다.
- 관리자(`ADMIN`)만 들어올 수 있는 API에 일반(`USER`) 회원이 접근하려고 하면 유저의 등급을 보고 접근을 막는다.

**<실패시 결과>**

- 인증은 완료했지만 등급이 낮아서 접근이 막히면 인가 실패
- HTTP 상태 코드로 **`403 Forbidden`** 에러를 반환

**<인가 코드 예시>**

로그인한 유저가 특정 API를 호출했을 때 해당 유저의 등급을 검사하는 과정

```java
@RestController
@RequestMapping("/api/admin")
public class AdminController {

@GetMapping("/dashboard")
@PreAuthorize("hasRole('ADMIN')") // ADMIN 권한을 가진 유저만 접근 허용
public ResponseEntity<String> getDashboard() {
return ResponseEntity.ok("관리자 대시보드 데이터");
}
}
```

- Stateful vs Stateless

> 서버가 client의 이전 상태를 기억하고 있는지
>

**[Stateful: 상태 유지]**

서버가 client의 이전 요청 및 상태 정보를 계속 기억하고 보존하는 방식이다.

클라이언트가 첫 번째 요청을 보내면 서버는 그 상태를 자신의 메모리나 저장소에 기록해 둔다. 두 번째 요청이 오면 서버는 이전에 기록해 둔 상태를 바탕으로 이어서 처리한다.

**<비유>**

```markdown
손님: "아메리카노 한 잔 주세요."

직원: "여기 있습니다." (직원이 손님이 아메리카노를 시켰다는 상태를 기억함)

손님: "방금 주문한 거 시럽 좀 추가해 주세요."

직원: "네, 넣어 드렸습니다." (이전 주문을 기억하고 있으므로 대화가 성립됨)
```

**<백엔드 구현 예시: 웹 서버의 세션>**

**웹 서버의 세션(Session)**이 대표적인 Stateful 방식으로 유저가 로그인하면 서버는 메모리(세션 저장소)에 "이 유저는 로그인한 유저다"라는 상태를 저장해 둔다. 유저가 다음 페이지로 이동할 때 세션 ID만 건네면 서버는 메모리를 뒤져서 "아, 아까 로그인한 홍길동이구나"라고 알아챈다.

**<장단점>**

- 클라이언트가 매번 많은 정보를 보낼 필요가 없어 편리
- 특정 서버가 그 유저의 상태를 쥐고 있기 때문에, 트래픽이 몰려 서버를 여러 대(Scale-out)로 늘릴 때 시스템이 매우 복잡해진다. (유저가 아까 1번 서버에서 로그인했는데 다음 요청이 2번 서버로 가면 로그인이 풀려버리는 문제 발생)

**[Stateless: 무상태]**
서버가 클라이언트의 이전 상태를 기억하지 않는 방식으로 모든 요청은 독립적이며, 요청 하나만으로 완벽하게 처리가 가능해야 한다.

서버는 과거를 기억하지 않으므로 클라이언트는 서버에 요청을 보낼 때, **해당 요청을 처리하는 데 필요한 모든 데이터(상태)를 매번 전부** 보내야 한다. 서버는 들어온 요청대로 응답을 준다.

**<비유>**

```markdown

손님: "아메리카노 한 잔 주세요."

알바생A: "여기 있습니다." (받고 퇴근)

손님: "시럽 좀 추가해 주세요."

알바생B: "네? 어떤 음료에 추가해 드릴까요? 아메리카노를 먼저 주문하시고 영수증을 보여주셔야 합니다."
(이전 맥락을 모르므로 손님이 필요한 정보를 다시 다 제공해야 함)
```

**<백엔드 구현 예시: HTTP 프로토콜, JWT 토큰 로그인>**
**HTTP 프로토콜은 기본적으로 Stateless**이므로 ****이를 활용한 **현대 REST API**와 **JWT** **로그인**이 대표적인 무상태 아키텍처이다.

서버는 유저의 로그인 상태를 갖고 있지 않는 대신 유저가 매 요청마다 "나 인증된 유저고 등급은 ADMIN이야"라는 정보가 디지털 서명으로 검증된 JWT 토큰을 헤더에 실어 보낸다. 서버는 토큰의 유효성만 체크하고 요청을 처리해 줄 뿐, 상태를 저장하지 않는다.

**<장단점>**

- **확장성이 좋다.** 서버가 상태를 안 들고 있으니 트래픽이 몰려서 서버를 늘려도, 클라이언트가 아무 서버에나 요청을 보내면 똑같이 처리해 준다. (클라우드/MSA 환경에 최적)
- 클라이언트가 매 요청마다 인증 정보나 필요한 데이터를 중복해서 채워 보내야 하므로, 네트워크 전송 데이터 용량(패킷 크기)이 커질 수 있다.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions mission/chapter08/mission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### 피어 리뷰

![에반_피어리뷰_제이의_워크북.png](./images/피어리뷰_PR리뷰_에반_8주차.png)