iframe
http.headers().frameOptions().disable(); // iframe 허용안함.
- iframe이란 inline frame의 약자
- iframe 요소를 이용하면 해당 웹 페이지 안에 어떠한 제한 없이 또 다른 하나의 웹 페이지를 삽입할 수 있다.
- 여기서 http.headers().frameOptions().disable() -> 이 iframe 요소를 허용하지 않겠다는 뜻!
CSRF
http.csrf().disable();
- https://www.youtube.com/watch?v=nzoUgKPwn_A
- 설명을 듣는 것보다 이렇게 해킹 기법을 실제로 보게 되니깐 더 이해가 가는 느낌이다.
- CSRF(교차 사이트 요청 위조)는 인증된 사용자가 현재 인증된 웹 애플리케이션에 강제로 요청을 제출하도록 하는 공격이다.
- CSRF 공격은 웹 애플리케이션이 인증된 사용자에 대해 가지고 있는 신뢰를 악용한다 (반대로 크로스 사이트 스크립팅(XSS) 공격은 사용자가 특정 웹 애플리케이션에 대해 갖고 있는 신뢰를 악용한다)
- 웹 애플리케이션이 개별 사용자가 생성한 요청과 사용자의 동의 없이 생성한 요청을 구분할 수 없는 경우 CSRF 공격은 웹 애플리케이션의 취약점을 악용한다.
- 여기서 csrf()설정을 disable 해둔 점은 postman을 사용할 수 없기 때문에 disable 설정을 넣어주었다.
CORS
http.cors().configurationSource(configurationSource());
public CorsConfigurationSource configurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*"); // GET, POST, PUT, DELETE (Javascript 요청 허용)
configuration.addAllowedOriginPattern("*"); // 모든 IP 주소 허용 (프론트 엔드 IP만 허용 react)
configuration.setAllowCredentials(true); // 클라이언트에서 쿠키 요청 허용
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
SessionCreationPolicy
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
- SessionCreationPolicy.ALWAYS: Always create an HttpSession: 항상 세션을 생성
- SessionCreationPolicy.IF_REQUIRED: Spring Security will only create an HttpSession if required: Spring Security는 필요한 경우에만 HttpSession을 생성
- SessionCreationPolicy.NEVER: Spring Security will never create an HttpSession, but will use the HttpSession if it already exists: Spring Security는 HttpSession을 생성하지 않으나, 이미 존재하는 경우 HttpSession을 사용한다.
- SessionCreationPolicy.STATELESS: Spring Security will never create an HttpSession and it will never use it to obtain the SecurityContext: Spring Security는 절대로 HttpSession을 생성하지 않으며, 이를 사용하여 SecurityContext를 가져오지도 않는다.
- SecurityContext: Interface defining the minimum security information associated with the current thread of execution.
- 현재 실행 스레드와 관련된 최소 보안 정보를 정의하는 인터페이스를 의미
formLogin()
http.formLogin().disable();
- formLogin을 사용하지 않고 JWT방식을 사용하기 때문에 disable() 설정 추가
- https://tech.toktokhan.dev/2021/04/30/JWT/
- https://youtu.be/1QiOXWEbqYQ
- Authentication: 쉽게 말해서 로그인. 내가 이 사이트에 가입된 사용자임을 아이디와 패스워드를 통해 인증을 받음
- Authorization: 인증을 받은 사용자가 이후 서비스의 여러 기능들을 사용할 때 서버가 로그인을 한 사용자라는 것을 알아보고 허가해주는 것
- JWT는 인가 Authorization에 연관된 기술
- 어떤 사이트나 서비스에 사용자가 로그인해있다는 사실을 서버가 인지할 수 있도록 하는 방법이 뭐가 있을까?
- 세션방식: 사용자가 로그인에 성공하면, 서버는 세션을 발행, 반으로 나눠서 반쪽은 사용자의 브라우저로 보내고, 다른 반쪽은 메모리(or 하드디스크, DB)에 올려놓는 것.
- 사용자의 브라우저(크롬, 엣지): 받은 반쪽을 Session ID란 이름의 쿠키로 저장(쿠키: 브라우저에 저장되는 정보). 로그인한 서비스에 요청을 보낼때마다 이 Session ID란 이름의 쿠키를 실어보낸다. 요청에 Session ID가 같이 넘어오면 서버는 메모리(DISK, DB)에 짝이 있는지 찾아서 있으면 인가(Authorization)을 해주는 것.
- Session ID를 사용해서 어떤 사용자가 서버에 로그인 되어있음이 지속되는 상태: "세션"이라고 함
- 서버가 재부팅하게 되면 메모리가 휘발되면서 모든 사용자는 로그인이 풀리게 된다.
- 서버가 복잡한 구성과 환경에서 어떤 상태를 기억해야 된다는게 설계하기 어려운 것.
- 부담이 많은 이 인가를 구현하기 위해 고안된 게 "토큰방식" JWT
- JWT: JSON Web Token
- 토큰방식이란?
- JWT를 사용하는 서비스에는 사용자가 로그인을 하면 토큰이라는 걸 넘겨준다.
- 세션은 반으로 나눠서 주었는데, 여기서는 그냥 토큰 전체를 주는 형식이다. -> 서버가 기억하고 있지 않는다
- 토큰 -> 인코딩 또는 암호화된 3가지 데이터를 이어붙인 것. header(헤더), payload(페이로드), verify signature(서명)로 구분
- 페이로드: Base64로 디코딩해보면 JSON형식으로 여러 정보들이 들어 있음. 토큰을 누가 누구에게 발급했는지, 이 토큰이 언제까지 유효한지, 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용(사용자의 닉네임, 서비스상의 레벨, 관리자 여부) 등을 서비스 측에서 원하는 대로 담을 수 있음. -> 이런 데이터를 Claim이라고 함.
- 헤더: 디코딩하면 두 가지 정보가 담겨 있음.
- type: 토큰의 타입 JWT를 의미
- alg: 알고리즘의 약자 -> 서명(verify signature)를 만드는데 사용될 알고리즘이 지정(HS256 등 여러 암호화 방식 중 하나를 지정)
- header와 payload, 서버에 감춰놓은 비밀 이 셋을 alg 암호화 알고리즘에 넣고 돌리면 서명값(verify signature)가 나오는 것
- 서버는 header와 payload의 값을 서버의 비밀 키와 함께 돌려봐서 계산된 결과값이 서명값(verify signature)과 일치하는 지 확인.
- 서명 값(verify signature)과 계산이 일치하고 유효기간도 지나지 않았다면 사용자는 로그인 된 회원으로서 인가를 받는 것
- JWT가 좋은가?
- 세션처럼 STATEFUL해서, 모든 사용자들의 상태를 기억하고 있다는 건, 기억하고 있는 대상의 상태들을 언제든 제어할 수 있다는 의미.
- 예) 한 기기에만 로그인 가능한 서비스를 만들려는 경우
- 세션 방식에서는 서버가 가지고 있는 세션을 제거하면 간단하게 제어가능. JWT에서는 이런 작업이 불가능
- 이미 준 토큰을 회수할 수 없고, 서버가 토큰을 추적하고 있는 것도 아니기 때문
- 혹은 토큰이 탈취당한 경우, 이 토큰을 무효화할 방법도 없는 것.
- 그래서 실 서비스에서 JWT로만 인가를 구현하는 곳은 그렇게 많지 않음.
httpBasic()
http.httpBasic().disable();
- 브라우저가 팝업창을 이용해서 사용자의 인증을 진행하는 것을 disable 해두었다.
http.authorizeHttpRequests()
http.authorizeHttpRequests()
.antMatchers("/api/s/**").authenticated()
.antMatchers("/api/admin/**").hasRole("" + UserEnum.ADMIN) // 최근 공식문서에서는 ROLE_ 안붙여도 됨
.anyRequest().permitAll();
- Authorize: 인가
- /api/s/** -> 인증된 사용자만
- /api/admin/** -> 여기로 오는 요청은 관리자 권한을 가진 사용자만 인가한다.
'CS지식들 > 공부공부' 카테고리의 다른 글
회원 가입 로직 구현 (1) | 2023.03.09 |
---|---|
인증(Authentication) 관련 Exception을 제어하는 기능 구현 (0) | 2023.03.09 |
동시성 문제 (3) (0) | 2022.12.19 |
동시성 문제 (2) (0) | 2022.12.19 |
동시성 문제 (1) (0) | 2022.12.18 |