이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Web Security는 어떤 순서로 학습해야 실무 판단으로 이어지는가?
- Spring Security 내부 구조보다 먼저 이해해야 하는 보안 모델은 무엇인가?
- 각 학습 단계에서 어떤 요청, 코드, 로그를 직접 확인해야 하는가?
개요
Web Security 학습은 Spring Security 설정 암기로 시작하면 쉽게 흔들린다. 설정 하나가 어떤 공격을 막는지 모르면 csrf().disable(), cors().configurationSource(...), JWT 필터 복사 같은 코드가 왜 안전하거나 위험한지 판단할 수 없다.
학습 순서는 요청 경계에서 시작하는 편이 좋다. HTTP 요청이 어디서 오고, 어떤 값이 클라이언트가 만든 값이며, 어떤 값이 서버가 발급한 값인지 구분해야 인증과 인가를 이해할 수 있다. 그 다음 브라우저 보안, API 입력, token, secret, 로그, 사고 대응으로 확장한다.
로드맵의 목표는 “많이 아는 것”이 아니라 “위험한 요청을 보면 어디서 막아야 하는지 설명하는 것”이다.
공격 시나리오
학습 순서가 잘못되면 다음과 같은 실수가 생긴다.
- JWT 필터 예제를 복사했지만 issuer, audience, expiry 검증을 모른다.
- CORS 오류를 없애려고 모든 Origin을 허용한다.
- CSRF를 끄면서 인증 방식이 쿠키인지 Authorization header인지 구분하지 않는다.
- 로그인 성공만 테스트하고 다른 사용자 리소스 접근은 테스트하지 않는다.
- 로그를 디버깅 문자열로만 남겨 사고 후 영향 범위를 알 수 없다.
이런 실수는 지식 부족보다 연결 부족에서 나온다. 각 보안 주제가 어떤 요청과 어떤 공격을 다루는지 순서대로 연결해야 한다.
취약한 요청/응답 예시
1. Spring Security JWT 예제 복사
2. CORS 에러 발생
3. 모든 Origin 허용
4. CSRF disable
5. 관리자 API는 프론트 라우터에서만 숨김
6. 로그는 log.info("error {}", token)이 흐름은 빠르게 동작할 수는 있지만 보안 판단 기준을 만들지 못한다. 문제가 생겼을 때 어떤 설정을 되돌려야 하는지도 알기 어렵다.
주제별 핵심 판단
- 학습 순서는 HTTP 경계, 인증, 인가, 브라우저 보안, API 입력, 운영 로그 순으로 잡는다.
- Spring Security 내부 구조보다 먼저 공격자가 어떤 값을 조작하는지 이해해야 한다.
- 각 주제는 취약 요청과 개선 요청을 비교하면서 익힌다.
- 마지막에는 사고 대응 플레이북으로 지식을 운영 행동까지 연결한다.
- 학습 결과는 체크리스트와 테스트 케이스로 남아야 한다.
추천 학습 순서
| 순서 | 주제 | 확인해야 할 질문 |
|---|---|---|
| 1 | 요청 흐름과 신뢰 경계 | 이 값은 누가 만들었고 어디서 검증되는가? |
| 2 | 인증과 세션 | principal은 어떻게 만들어지고 언제 폐기되는가? |
| 3 | 인가와 소유권 | 로그인한 사용자가 이 resource에 이 action을 해도 되는가? |
| 4 | 브라우저 보안 | 쿠키, Origin, DOM 실행 모델이 요청에 어떤 영향을 주는가? |
| 5 | API 입력과 오류 | 어떤 입력을 허용하고 어떤 오류를 숨길 것인가? |
| 6 | token과 secret | 발급, 저장, 검증, 회전, 폐기를 어떻게 다룰 것인가? |
| 7 | 로그와 사고 대응 | 사고 후 누가 무엇을 했는지 복원할 수 있는가? |
개선된 요청/응답 예시
1. 보호 자산과 신뢰 경계 작성
2. 취약 요청과 개선 요청 비교
3. Spring Security 설정이 막는 공격 이름 기록
4. Service 권한 검사와 Repository 조건 확인
5. 실패 케이스 테스트 작성
6. 감사 로그 event 이름과 필드 정의
7. 사고 대응 시 어떤 조치를 할지 문서화이 흐름은 설정을 외우기보다 판단 기준을 만든다. 새로운 기능이 생겨도 같은 질문을 반복할 수 있다.
방어 설계
- 각 챕터를 읽을 때 “이 주제의 공격자는 무엇을 바꾸는가”를 먼저 적는다.
- Spring Security 설정은 “막는 공격”과 “남는 우회 경로”를 함께 기록한다.
- 코드 예시는 성공 경로보다 실패 경로를 먼저 확인한다.
- 브라우저 보안은 프론트 구현이 아니라 서버 응답과 인증 저장 방식의 문제로 본다.
- token 학습은 구조보다 검증 실패, 재발급, 폐기, 탈취 대응을 포함한다.
- 로그 학습은 문자열 출력이 아니라 감사 가능한 이벤트 설계로 확장한다.
- 사고 대응은 마지막 장식이 아니라 모든 보안 설계의 검증이다.
Spring/HTTP 예시
@SpringBootTest
@AutoConfigureMockMvc
class OrderSecurityTest {
@Test
void otherMemberCannotReadOrder() throws Exception {
mockMvc.perform(get("/api/orders/{orderId}", 2002)
.with(jwt().jwt(jwt -> jwt.subject("member-1004"))))
.andExpect(status().isForbidden());
}
}학습 결과는 테스트로 고정되어야 한다. 문서에서 “권한 확인이 필요하다”고 배워도 테스트가 없으면 다음 기능에서 같은 실수가 반복된다.
운영 로그와 감사 지점
level=WARN event=security_test_case_added topic=authorization scenario=other_member_order_read result=covered owner=backend traceId=doc-roadmap학습 로드맵 자체도 운영과 연결할 수 있다. 중요한 보안 학습은 체크리스트, 테스트 케이스, 리뷰 질문으로 남아야 팀 지식이 된다.
- 새 기능을 만들 때 어떤 보안 문서를 참조했는지 기록한다.
- 실패 케이스 테스트가 없는 기능은 리뷰에서 막는다.
- 보안 설정 변경은 릴리스 노트에 남긴다.
- 로그 이벤트 이름은 문서와 코드가 같은 용어를 쓰게 한다.
- 사고 대응 후에는 관련 학습 문서를 업데이트한다.
실전 판단 기준
- 설정 복사보다 취약 요청을 먼저 만들어 보아야 한다.
- 각 주제마다 “막는 공격”과 “테스트 방법”을 같이 정리해야 한다.
- 문서, 코드, 테스트, 로그가 같은 보안 정책을 말하는지 본다.
- 학습 순서가 프레임워크 내부 설명으로만 흐르지 않게 조정한다.
- 좋은 판단은 지식을 사고 대응 행동으로 바꿀 때 나온다.
테스트 포인트
- 각 보안 주제마다 취약 요청과 개선 요청을 하나 이상 작성했는지 확인한다.
- 설정 변경마다 해당 설정이 막는 공격 이름이 문서에 남아 있는지 확인한다.
- 인증 없음, 권한 없음, 만료 token, 잘못된 Origin, 예상 밖 필드 테스트가 있는지 확인한다.
- 보안 이벤트 로그가 테스트나 운영 시나리오와 연결되는지 확인한다.
- 사고 대응 문서가 실제 token 폐기, 세션 무효화, 권한 회수 절차를 포함하는지 확인한다.
위험 신호!
- Spring Security 예제를 먼저 복사하고 공격 모델은 나중에 생각한다.
- CORS, CSRF, JWT, Session을 “로그인 설정”으로 한꺼번에 묶어 이해한다.
- 보안 문서에는 설명이 있지만 테스트와 로그에는 반영되지 않는다.
- 실패 케이스보다 성공 케이스 위주로만 학습한다.
- 사고 대응을 배포 이후 운영팀의 일로만 본다.
확인 질문
확인 질문
- Web Security 학습의 첫 단계는 무엇인가?
- HTTP 요청 흐름과 신뢰 경계를 그리는 것이다.
- Spring Security 설정을 배울 때 반드시 함께 적어야 하는 것은 무엇인가?
- 해당 설정이 막는 공격과 남는 우회 경로, 실패 로그다.
- 학습이 실무 판단으로 이어졌는지 어떻게 확인하는가?
- 취약 요청, 개선 코드, 실패 테스트, 감사 로그, 사고 대응 절차로 남아 있는지 확인한다.