슈퍼코딩/주특기(JAVA)

2024.06.07(금) 슈퍼코딩 신입연수원 10주차 Day 5 후기 - Spring Security, 보안기초

곰돌이볼 2024. 6. 7. 15:49
  • 강의
    • 113강(Spring Security v3) ~ 117강(wrap-up)

Spring Security


  • Java 기반 보안 프레임워크
  • 기능
    • 인증Authentication) : 신원 확인
    • 권한 부여(Authorization ) : 특정 자원이나 작업에 대한 접근 권한 확인
    • 세션 확인 : 사용자 세션 보호, 동시 세션 제어, 세션 고정 보호 등의 기능 제공
    • CSRF 방지 : CSRF 공격 방지 기능 제공
  • 인증
    • Authentication
    • 유저 확인
  • 인가
    • Authorization
    • 유저 권한 확인 및 허가
  • 로그인 인증 처리 과정
    • AuthenticationFilter, UserDetails, UserDetailsService 구현하기

  • 설정
    • 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-security'

 

  • 의존성만 추가한 경우
    • 포스트맨의 Basic Auth에 {username : root, password : 아래 생성된 값 } 넣으면 동작됨

 

  • 구현하기
    • AuthenticationFilter
      • JwtTokenProvider : JWT를 생성하고, 검증하며, JWT로부터 인증 정보를 추출하는 역할
      • JwtAuthenticationFilter : HTTP 요청을 가로채 JWT를 확인하고, 이를 통해 인증 정보를 추출하여 SecurityContext에 설정하는 역할
    • UserDetails : UserDetails 인터페이스를 상속 받아서 구현하기
      • getAuthorities : 권한 가져오기
      • getPassword : 패스워드 설정 , 유저 인증할 때 사용
      • getUsername : 유저 ID 정보, 유저 인증할 때 사용
    • UserDetailsService : UserDetailsService 인터페이스를 상속 받아서 구현하기
      • loadUserByUsername : username에 해당하는 사용자를 찾아서 userdetail 객체 생성해서 반환하기

보안지식


XSS

  • Cross Site Scripting
  • 사용자가 웹 페이지에 악성 스크립트 삽입을 통한 해킹
  • 의도적인 스크리팁 삽입을 통해서 쿠키 보내기 설정되고, 이를 통해서 서버 해킹이 발생
  • 방지 방법
    • 글 작성 시 스크립트 등록을 못하도록 설정
    • 중요한 Cookie HTTPOnly 및 Secure 설정

CSRF

  • Cross Site Request Forgery
  • 사용자의 세션이나 토큰을 이용해서 다른 명령 실행하기
  • 방지 방법
    • HTTP의 Referer이나 HOST 이름 비교
    • CAPTCHA를 통해서 사람인지 확인

SQL Injection

  • 서버 요청 시 악의적인 DB SQL문을 주입하는 해킹 방법
  • 방지 방법
    • 여러 IF문을 통한 검증 로직 추가
    • JPA 사용

 

SOP

  • Same Origin Policy
  • 브라우저는 기본적으로 SOP 사용
  • 외부에서 얻은 데이터는 항상 같은 Origin이어야함

Origin

  • 출처
  • 동일한 origin 판단 여부 : URI의 Protocol + Host + Port가 동일해야 함
  • ex) http://example.com과 http://example.com:8080은 다른 origin임

CORS

  • Cross-Origin Resource Sharing
  • front-end와 back-end 소통 시 발생할 수 있는 문제
  • 해결방법
    • 브라우저 플러그인
    • 백엔드 전역 보안 설정
  • 실습 - CORS 브라우저 플러그인

  • 실습 - CORS 백엔드 전역 보안 설정
package com.github.supercodingspring.config.security;

import com.github.supercodingspring.web.filters.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;
import java.util.List;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtTokenProvider jwtTokenProvider;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.headers().frameOptions().sameOrigin()
                .and()
                .formLogin().disable()
                .csrf().disable()
                .cors().configurationSource(corsConfigurationSource()) // CORS 설정
                .and()
                .httpBasic().disable()
                .rememberMe().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                    .antMatchers("/resources/static/**", "/v1/api/sign/*").permitAll()
                    .antMatchers("/v1/api/air-reservation/*").hasRole("USER")
                .and()
                .exceptionHandling()
                    .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                    .accessDeniedHandler(new CustomerAccessDeniedHandler())
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("http://localhost:63342"));
        configuration.setAllowCredentials(true); // token 주고 받을 때,
        configuration.addExposedHeader("X-AUTH_TOKEN"); // token
        configuration.addAllowedHeader("*");
        configuration.setAllowedMethods(Arrays.asList("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS"));
        configuration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
  • 환경변수
    • 서버 코드에서 공개되면 안되는 코드를 환경변수로 설정해서 사용함
    • 설정 방법
      • 로컬 컴퓨터 '환경변수'
      • 코드에서는 환경변수로 실제 값 숨기기
    • @ConfigurationProperties : 여러 개의 환경변수를 한번에 가져올 때 사용
    • @Value : 한 개의 환경변수를 가져오기 위해서 사용
// application.yml
datasource:
	username: 123
	password: 1234

// build.gradle
dependencies {
    annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}

// 가져오기.java
@Getter
@Setter
@ConfigurationProperties(prefix = "datasource")
public class DataSourcePropertries {
	private String username;
    private String password;
}

// 사용하기.java
@EnableConfigurationProperties(DataSourcePropertries.class)
@RequiredArgsConstructor
public class JdbcConfig {
	private final DataSourcePropertries dataSourcePropertries;
    
    public void test() {
    	System.out.println("username : " + dataSourcePropertries.getUsername());
    }
}
// application.yml
jwt:
	secret-key-source : ${JWT_SECRET_KEY}

// 환경변수 설정 사용하기
public class JwtToeknProvider {
	@Value("${jwt.secret-key-source}")
	private String secreKey;

}

 

 

Spring 커리큘럼 확인하기

https://github.com/woowacourse/back-end-roadmap