본문 바로가기
📕 Spring Framework/Spring Project

2022.05.11 「SHA-256 + Salt & 인증」

by GroovyArea 2022. 5. 11.
인증 관련해서 사실 스프링 시큐리티를 사용해도 괜찮지만 순차적으로 가기 위해서 순수하게 SHA-256 암호화 알고리즘을 이용해 비밀번호 암호화와 로그인을 원시적으로 구현한 하루다..
거진 12시간을 삽질한 것 같다.
암호화 알고리즘 이용과, Mybatis 매핑 문제도 있고, ModelMapper를 사용해 DTO VO 매핑이 계속 안되어서 하루 종일 멘털이 나갔었다. 다른 공부도 할게 너무 많은데 프로젝트만 비중이 많았던 하루라 너무 아쉽다. 하지만 삽질한 만큼 내 것이 되었으면 좋겠다.

오늘은 하루종일 삽질한 내용을 기반으로 한번 정리를 해보려고 한다.

여담으로 다이어트중인데 요새 상주하는 공부 환경에서 오트밀 미니 바이트를 제공해주는데 이거 진짜 너무 맛있다..
예전엔 진짜 단 거 잘 참았는데 늙었나 보다.
하루에 4, 5개는 먹는다.. 좀 참아야 되는데 식욕 억제가 너무 힘든 것 같다~

 

SHA-256 + Salt 

스프링에서 제공하는 Bcrypt 라이브러리를 사용해서 비밀번호 암호화를 구현 가능하지만,

보편적으로 많이 사용하는 단방향 암호화 알고리즘 SHA-256과 첨가물을 섞어 같은 비밀번호라도 유저마다 다른 비밀번호를 생성시키려고 적용해보았다.

public static String getSalt() {
        Random random = new Random();
        byte[] salt = new byte[10];

        random.nextBytes(salt);

        StringBuffer sb = new StringBuffer();

        for(int i=0; i<salt.length; i++) {
            sb.append(String.format("%02x", salt[i]));
        }

        return sb.toString();
    }

    public static String getSecurePassword(String pwd, String salt) throws NoSuchAlgorithmException {

        byte[] saltArr = salt.getBytes();
        String result = "";

        byte[] temp = pwd.getBytes();
        byte[] bytes = new byte[temp.length + saltArr.length];


            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(bytes);

            byte[] b = md.digest();

            StringBuffer sb = new StringBuffer();

            for(int i=0; i<b.length; i++) {
                sb.append(Integer.toString((b[i] & 0xFF) + 256, 16).substring(1));
            }

            result = sb.toString();

        return result;
    }

첨가물을 생성하는 메서드 

- 랜덤 한 값들을 생성한 byte배열 크기만큼 String 값으로 변환하여 반환한다.

 

암호화된 비밀번호를 만드는 메서드 

- 입력 비밀번호와 첨가물을 매개변수로 넘겨 SHA-256 암호화 알고리즘을 사용하여 배열을 업데이트시키고 16진수를 기반으로 암호화된 비밀번호를 생성해 반환한다.

 

테스트 코드로 add 해보았다

유저 칼럼에는 비밀번호가 암호화가 잘 되어 저장된다.

첨가물도 데이터로 저장해야 로그인 인증이 가능하다.

 

 

DTO, VO 매핑

어제 modelMapper를 알게 되어 라이브러리를 빌드해 사용했다.

오늘 갑자기 매핑이 안 되는 사달이 났다.

무엇이 문제이냐? 계속 null만 받는다.

 

 

has a non-private no-argument constructor. 

=> 이런 에러가 계속 뜬다.

그래서 기본 생성자를 만들어줬다.

 

@Bean
public ModelMapper modelMapper() {
    ModelMapper modelMapper = new ModelMapper();
    modelMapper.getConfiguration()
            .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
            .setFieldMatchingEnabled(true);
    return modelMapper;
}

field 접근 level을 private으로 바꿔줬다. 된다.

 

이번엔 Mybatis 매핑이 안된다?

 

결론은 modelmapper는 고쳤지만 mybatis에서 매핑에 문제가 있었던 것 같다.

 

내가 사용하고 싶은 VO

불변 객체.

즉, setter가 없게 하고 싶다. 

그래서 allargsConstructor만 만들고 getter만 있다.

 

MyBatis 매핑 원리

1. 클래스에 setter가 있으면 setter를 호출한다.

2. setter가 없다면 필드 이름으로 맵핑한다.

3. 직접 정의한 생성자(모든 필드가 있는 생성자 포함)는 DB 출력 칼럼 순서와 생성자에 정의된 파라미터 순서가 같아야 한다.

4. 기본 생성자 또는 순서를 맞춘 모든 필드가 있는 생성자를 반드시 생성해주자

 

하여 resultMap 이용했다. 다 매핑해줬다.

 

modelMapper도 잘 동작하고 mybatis도 칼럼 매핑을 이제야 잘해준다!!!!

 

결론

암호화 알고리즘은 이해하는데 시간이 좀 걸렸지만

mybatis와 modelmapper 매핑 관련해서 시간을 많이 잡아먹었다. 그리고 내가 mybatis 개념이 부족했었나 보다. 한창 수업 들을 때 제일 이해가 안 가던 부분이 mybatis였는데 프로젝트를 직접 하니까 이렇게 허점이 드러난다. 이번 기회에 확실히 알고 가야겠다. 삽질한 만큼 더 성장해보자~

 

반응형