Spring Security 6 튜토리얼 (4)

Sorrynthx Kim·2023년 8월 23일
1

암호관리 방식

🟢 [인코딩 (Encoding)]
인코딩은 데이터를 한 형태에서 다른 형태로 변환하는 과정으로 정의되며, 암호학과는 관련이 없습니다.

이 과정은 비밀이 없으며 완전히 되돌릴 수 있습니다.

인코딩은 데이터를 보호하는 데 사용될 수 없습니다. 다음은 인코딩에 사용되는 다양한 공개적으로 사용 가능한 알고리즘입니다.

예: ASCII, BASE64, UNICODE

🟢 [암호화 (Encryption)]
암호화는 기밀성을 보장하는 방식으로 데이터를 변환하는 과정으로 정의됩니다.

기밀성을 달성하기 위해, 암호화는 암호학 용어로 "키"라고 부르는 방식을 사용해야 합니다.

"키"의 도움으로 복호화를 사용하면 암호화를 되돌릴 수 있습니다. "키"가 기밀인 한, 암호화는 안전한 것으로 간주될 수 있습니다.

🟢 [해싱 (Hashing)]
해싱에서는 해싱 함수를 사용하여 데이터를 해시 값으로 변환합니다.

한 번 해싱된 데이터는 되돌릴 수 없습니다. 생성된 해시 값에서 원래 데이터를 알 수 없습니다.

임의의 데이터와 해싱 알고리즘의 출력이 주어지면 원래 입력 데이터와 일치하는지 확인할 수 있으며 원래 데이터를 볼 필요가 없습니다.

노출 되도 상관없는 데이터 -> 인코딩 (ex. 카테고리)
DB에서 꺼낸 뒤 다시 볼 데이터 -> 암호화 (ex. 핸드폰, 이메일)
다시 볼 필요 없고, 확인만 필요한 데이터 -> 해싱 (비밀번호)

암호화 프로세스

해싱된 비밀번호를 DB에서 가져온 뒤, 맞는지만 확인.

PasswordEncoder 메소드

보통 BCryptPasswordEncoder 많이 사용

encode : 암호화 메소드
mathces: 일치 여부 확인
upgradeEncoding: 더 강력하게 업그레이드 해야 하는지 확인 (시간이 지남에 따라 덜 안전해지는 경우)
upgradeEncoding 예시
@Override
public boolean upgradeEncoding(String encodedPassword) {
    // Check the encoding algorithm used for the password
    // Return true if an upgrade is needed, false otherwise
    return !encodedPassword.startsWith("{bcrypt}");
}

🟣 코드

스프링부트 3.1.2
자바: OpenJDK 17
Gradle: 8.3

🟢 ProjectSecurityConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class ProjectSecurityConfig {
	
	@Bean
	SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        
		// csrf 비활성화 (사이트 요청 위조) ---> csrf 토큰이 없어도 서버는 응답
		// 스프링에서는 csrf 기본은 활성화 (보안 목적) ---> csrf 토큰을 url에 포함해야 서버는 응답
		http.csrf((csrf) -> csrf.disable()) 
                .authorizeHttpRequests((requests)->requests
                        .requestMatchers("/myAccount","/myBalance","/myLoans","/myCards").authenticated()
                        .requestMatchers("/notices","/contact","/register").permitAll())
                .formLogin(Customizer.withDefaults())
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
	
    
}

🟢 LoginController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.springsecurity63.model.Customer;
import com.example.springsecurity63.repository.CustomerRepository;

@RestController
public class LoginController {

    @Autowired
    private CustomerRepository customerRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @PostMapping("/register")
    public ResponseEntity<String> registerUser(@RequestBody Customer customer) {
        
    	Customer savedCustomer = null;
        ResponseEntity response = null;
        
        try {
            // encrypt
        	String hashPwd = passwordEncoder.encode(customer.getPwd());
            customer.setPwd(hashPwd);
            
            // save
        	savedCustomer = customerRepository.save(customer);
        	
            if (savedCustomer.getId() > 0) {
                response = ResponseEntity
                        .status(HttpStatus.CREATED)
                        .body("Given user details are successfully registered");
            }
        } catch (Exception ex) {
            response = ResponseEntity
                    .status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("An exception occured due to " + ex.getMessage());
        }
        return response;
    }

}

결과

만약 id 2번으로 로그인 시도 시,

자격 증명 실패

소스코드:
https://github.com/sorrynthx/Spring-Boot

그 다음에는 Implement and Customize the Authentication Provider에 대해서 작성.

profile
https://github.com/sorrynthx/Spring-Boot/tree/main/springsecurity

0개의 댓글

관련 채용 정보