Home > Today I Learned > 2026_05_11~2026_05_15 > 2026-05-15 일지

2026-05-15 일지
spring security

Spring Security


HTML 폼태그 방식


HTML 폼을 통해 사용자 ID와 비밀번호를 입력받아 서버에서 검증하는 방법. 기본 설정
유저네임인증필터

사용자 로그인 요청

  1. /login 으로 POST 요청
  2. UsernamePasswordAuthenticationFilter가 요청 가로챔
    • 이 필터는 Spring Security에서 폼 로그인 인증을 처리하는 필터
  3. username, password 추출
  4. AuthenticationManager에게 인증 요청
  5. UserDetailsService 등을 통해 사용자 정보 조회
  6. 비밀번호 검증
  7. 인증 성공 시 SecurityContext에 인증 정보 저장
  8. 실패 시 로그인 실패 처리

정보 보안 3요소(CIA)


  • Confidentiality(기밀성) : 정보를 볼 수 있는 사람만 볼 수 있어야 한다. 잠그는 것을 의미
  • Integrity(무결성) : 정보가 함부로 바뀌지 않고, 정확하게 유지해야 한다. 무단수정 x
  • Availability(가용성) : 필요할 때 정보를 사용할 수 있는 상태. 정보는 적합한 인증 절차를 통과했으면 원할 때, 바로 사용 할 수 있어야 한다.

XSS, 크로스사이트 스크립트


사이트에 악성 자바스크립트를 숨겨 놓는것, 이를 통해 우리를 운영하는 페이지를 통해 고객들을 공격하는 것이다. 하지만 브라우저는 이에 대한 검사를 해주지는 못한다.

여기서 자바스크립트는 어떤 스크롤을 누르고 있는지, 키보드, 마우스의 위치에 대해 캡쳐링이 가능하다. 이러한 데이터를 다른 곳에 통신을 통해 보내는 것이 가능하여 조심해야 한다.

CSRF Cross Site Request Forgery


Forgery는 위조라는 의미로 , 사용자의 공격을 다른 사이트로 보내는 것을 의미한다.

위조된 사이트를 이용해서 진짜로 인증받은 다른 정보를 편취(갈취)해서 요청을 보내서 정보를 갈취하는 행동

위조 지폐랑 비슷한 느낌, 사용자가 이게 위조되었는지 잘 모른다. 개발자가 똑같은 사이트로 클론코딩하는 것이 가능하다. 위조된 사이트에서 googe처럼 피싱을 유도하는 기능을 수행한다. 이거를 어떻게 막을 수 있을까? CSRF 토큰이 있다.

CSRF 토큰은 html 페이지를 내려줄 때 키를 쌍으로 발급한다. 이 키는 반대쪽 키가 있어야 돌아가는 키이다. 한쪽은 내가 세션에다가 묶어두고 하나는 내가 내려준 응답 어딘가에 비밀스럽게 넣어준다. 인증이 들어왔을때는 이 두가지 키를 이용하여 검증을 수행하는 것

내가 내려준 응답에 대해서만 보안을 적용하겠다는 의미이다.
이러한 csrf 토큰을 사용하지 않는다면 spring security를 적용한 웹을 사용한다면 403에러가 뜨게 되어있다.

CORS Cross-Origin Resource Sharing


CORS에러는 웹 개발시 나타날 수 있는 에러 종류 중 하나이다. 동일 출처 정책(same-origin policy)를 어긴 경우 중 하나인데 동일 출처 정책은 xss, csrf와 같은 공격을 방지하기 위해 동일한 출처에서만 리소스를 공유할 수 있다라는 법률이다.

배포할때는 이를 조심해야 한다. 다 똑같이 적용해야 한다. thymeleaf 이에 관한 대책이 세워져 있지만 다른 프론트엔드 언어를 사용하여 구현할 때는 이를 조심해야 한다.
→ 이 문제는 브라우저에서 잡는 것이다.

출처가 의미하는 것이 무엇인가. 프로토콜, 도메인, 포트가 출처를 의미한다.
스키마가 프로토콜이다. 도메인과 포트까지 본다. 다른 프로토콜, 도메인, 포트에 대해 읽을 수 있어야 한다. 우리사이트에 있는 정보를 이용해도 되는가?
허용된 친구들만 우리서버의 자원들을 가지고 갈 수 있게 묶어두는 것이 필요하다.

하지만 개발을 하다보면 어쩔수 없이 다른 출처간의 상호작용을 해야하는 케이스가 존재한다. 이와 같은 예외상황에서 적용가능한 것이 CORS 정책이다. SOP정책을 위반해도 CORS정책에 따르면 다른 출처의 리소스도 허용이 된다.

웹브라우저가 보안상 다른 도메인의 서버 자원에 접근하는 것을 제한하는 SOP를 우회하여 안전하게 자원을 공유하도록 허용하는 HTTP 헤더 기반 메커니즘, 다른 출처의 자원 공유에 대한 정책이다.

브라우저의 CORS 기본동작


  1. 클라이언트에서 http 요청의 헤더에 Origin을 담아 전달
  2. 서버는 응답헤더에 Access-Controll-Allow-Origin을 담아 클라이언트로 전달
    • 이 리소스에 접근하는 것이 허용된 출처 url을 내려보낸다.
  3. 클라이언트에서 Origin과 서버가 보내준 Access-Controll-Allow-Origin을 비교한다.
    • 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과 서버가 보내준 응답의 Access-Control-Allow-Origin을 비교한후 차단할지 말지를 결정

서버에서 Access-Controll-Allow-Origin 헤더에 허용할 출처를 기재해서 클라이언트에 응답을 하면 되는 것

암호화


중요한 내용을 아무나 알아보지 못하도록 바꾸어 놓는 것
크게 단방향, 양방향으로 종류가 나뉘게 된다.

단방향은 한번 암호화를 하면 원래로 못돌아간다. 일방통행이다. 암호화는 될 수 있지만 복호화는 될 수가 없다. 이를 통해 나오는 어떠한 값을 해시 값이라고 부른다. 암호화 된 값을 원본으로 되돌린다면 이것을 구분할 수 있을까? → 단방향 암호화를 하면 항상 똑같은 해시값이 나오기 때문에 이 해시값과 비교를 해서 값이 옳은지를 확인을 한다.

양방향은 암호화 한 내용을 다시 복호화 할 수 있는 것이다. 모르는 기호를 다시 복호화를 하여 복구를 하는 것이다. 단방향과 양방향의 차이는 원래값으로 되돌릴 수가 있는가? 우리는 단방향으로 로그인을 구현한다.

실무에서는 비밀번호는 암호화 되서 들어가게 된다. 예를 들어 중국의 “모르면 괜찮아 안걸리면 돼” 걸리기 전까지는 내는 것은 없지만 걸리면 2배이상으로 는 경우가 있다. 이렇게 행동하는 것을 방지하기 위해 Spring Security에는 나오는 비번이 평문이면 해킹당했다고 취급하고 로그인을 거부하게 된다.

우리 업계에서 표준처럼 사용하는 암호화 알고리즘 Bcrypt, 크립토 툴 → 암호화 툴, 단방향 암호화 방식이다. 정확히는 비밀번호 해싱함수이다. Bcrypt의 원리는 이 암호화 해시안에서 되게 긴 문자열을 만들고 섞게 된다. 아이디 별로 섞게 된다. 이렇게 만들어 놓는 것을 Salt라고 한다. 양념친다, 소금친다 이러한 느낌으로 사용된다고 한다.

Bcrypt는 암호화를 할때마다 다른 salt가 나오도록 했다.
스프링 시큐리티는 이러한 Bcrypt 방식을 차용해서 사용한다

Bcrypt

Bcrypt : 업계 표준 암호화 알고리즘으로, 비밀번호 해시 방식을 사용하며 단방향 암호화이다.

솔트(Salt) 생성하고, 비밀번호와 솔트를 결합한 뒤, Blowfish 암호화 알고리즘을 기반으로 바이트를 수천 번 섞고 연산(Round)하는 방식이다.

  • Salt : 단방향 함수의 추가 입력으로 사용되는 랜덤 데이터 문자열
  • 암호화 할때마다 솔트값을 다르게 하여서, 동일한 값이어도 암호화 할 때마다 다르게 저장된다.

해시 형태 : $[버전]$[cost]$결과

OAuth2.0 방식


권한을 위임하는 프로토콜. 신용 있는 서비스들에게 인증의 책임을 위임을 한다. 이런 서비스들이 개인정보를 보관하고, 책임을 지게된다.

oauth2.0

Resource Owner

리소스 소유자. 우리의 서비스를 이용하면서, 구글, 페이스북 등의 플랫폼에서 리소스를 소유하고 있는 사용자이다. 리소스라 하면 ‘구글 캘린더 정보’, ‘페이스북 친구 목록’, ‘네이버 블로그 포스트 작성’ 등이 해당된다.

Authorization & Resource Server

Authorization Server는 Resource Owner를 인증하고, Client에게 액세스 토큰을 발급해주는 서버이다. Resource Server는 구글, 페이스북, 트위터와 같이 리소스를 가지고 있는 서버를 말한다.

  1. 인증 요청 : 고객이 인증 요청
  2. 권한부여 승인코드 요청 : 구글에 개인정보 요청. 개인정보를 얻을 수 있는 토큰을 요청
    로그인 페이지 : 고객이 구글 로그인
  3. 인증 (구글이 인증 해줌)
  4. 권한부여 승인코드 전달
  5. AccessToken 요청 : 권한부여 승인코드로 구글 인증 서버에 AccessToken을 요청
  6. AccessToken 전달 : 인증서버가 권한부여 승인코드가 유효한지 검토하고 AccessToken을 전달
  7. 자원 요청 : AccessToken으로 Resource Server에 개인정보 요구
  8. 자원 전달 : Resource Server가 AccessToken 검증후 그에 맞는 개인 정보 전달
  9. 인증완료
    • Yaml 파일 설정하면 Spring Security가 1~8번을 해줌

인증 완료 후에는 서버-구글 간의 AccessToken 만료기간까지 유지.
개인 정보 접근 범위는 우리가 설정 한 것 및 고객의 동의를 의미한다.

AccessToken은 매우 민감하고 중요한 코드이므로, 보관시 무조건 양방향 암호화 해서 보관하거나, 폐기

JWT (Json Web Token)


jwt-token.png

식별하기 위하여 웹에서 사용하는 문자열 키. 디코딩 하면 JSON 형태이다
\한 번 만들면 철회 불가 하며, 민감한 정보를 빠르게 만들 수 있다는 장점이 있다.

  • OAuth2.0을 한다고 해서 JWT 토큰을 필수적으로 사용 할 필요는 없음.

구조 : 헤더.페이로드.시그니쳐, jwt는 검은색 .을 기준으로 3가지로 분류된다

  • 헤더 : 서명을 암호화한 알고리즘의 이름
  • 페이로드 : 토큰의 정보인 본문. 페이로드는 아무나 다 내부를 볼 수 있다. 따라서 민김한 정보를 페이로드에 넣으면 안 된다.
  • 시그니쳐 : 암호화된 서명. (단방향 암호화를 하고 압축함)

JWT 토큰은 문자열이다. 한번 만들면 철회가 불가능하다.문자열은 한번 만들면 철회가 안된다. jwt는 유효기간이 있는데 한번 노출되면 유효기간이 끝날 때까지 유효하다. 이것을 보완상충하기 위한 전략이 있다. access token과 Refresh token으로 분리하여 access token을 짧은 수명을 가진 것으로 활용하고 새로운 Access Token을 재발급하는데 Refresh token을 사용하게 된다.

http 특성으로는 비연결성과 비상태성이 있다. 이 중 비상태성을 가지는데, 똑같은 것이 보낸 것은 어떻게 기억하고 있을까?

쿠키하나를 세팅해준다. localhost를 가면 JSESSIONID가 있다. 이는 spring boot + spring security에서의 기본 세션 쿠키 이름이다. 여기서 이것을 없애면 세션을 찾을 수 없게 되고 다시 로그인을 해줘야 한다.

브라우저에서는 jsessionID라는 세션으로 쿠키로 기억하고 있다. 스프링 세큐리티가 생각보다 많은 것을 해줄수 있게 된다. 스프링 시큐리티의 원리는 필터가 들어간다. 필터로 이루어진 필터 체인이 있다.