SHA256 암호화 알고리즘을 이용한 회원가입, 로그인

김성인·2023년 6월 28일
2

🍃 SpringBoot

목록 보기
2/18

회원가입시 유저의 비밀번호를 단방향으로 암호화하기 위해 "SHA256 알고리즘"을 선택

참고 블로그 및 스크랩

  1. SHA256 기본 구조 및 salt 사용 안내
    -> https://cocoon1787.tistory.com/832

  2. SHA256 검증 사이트
    -> https://coding.tools/kr/sha256

  3. SHA256에 사용되는 MessageDigest 클래스 설명
    -> https://ktko.tistory.com/entry/MessageDigest%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%B0%94%EC%9D%98-Hash-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

  4. 바이트 스트림을 32bit로 변환하여 음수를 처리하는 방법
    -> https://vmpo.tistory.com/111

🔒SHA256.Java

public class SHA256 {
    public SHA256() {
    }

	// 0)
    public static String createSalt(String plainText) throws NoSuchAlgorithmException {
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        byte [] bytes = new byte[16];
        random.nextBytes(bytes);

        //SALT 생성
        String salt = new String(Base64.getEncoder().encode(bytes));

        //System.out.println("{SHA256.Class} salt : " + salt);
        return salt;
    }

    public static String encrypt(String plainText, String salt) {
        try {
            // 1) 
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            String rawAndSalt = plainText + salt;
            //System.out.println("{SHA256.Class} rawAndSalt : " + rawAndSalt);

            // 2) 
            md.update(rawAndSalt.getBytes());

            // 3) 
            byte[] byteData = md.digest(); // 1byte = 8bit

            // 4)
            StringBuffer hexString = new StringBuffer();
            for(int i = 0; i < byteData.length; ++i) {
                String hex = Integer.toHexString(255 & byteData[i]);
                if (hex.length() == 1) {
                    hexString.append('0');// 각 byteData당 두 자리 수 16진수로 변환
                }
                hexString.append(hex);
            }

            return hexString.toString();

        } catch (Exception var7) {
            var7.printStackTrace();
            throw new RuntimeException();
        }
    }
}

🔒설명

PlainText -> SHA256(Hash Algorithm) -> CipherText
형태의 단방향 암호화를 진행하고, 암호화 키가 존재하지 않기 때문에, 복호화도 불가능하다.

1. PlainText + salt값으로 해시 값 계산

  • 해시값 계산을 하기위한 MessageDigest 클래스에 SHA 256 알고리즘을 옵션으로 선택

2. MessageDigest.update()

  • 메소드 호출할 때 마다 객체 내에 저장된 digest 값이 계속해서 갱신
  • digest 값은 평문의 HashValue

3. HashValue를 (1)Byte타입으로 리스트 변환

  • digest()메서드를 호출하여 객체내 digest 값 반환
  • 바이트배열로 해쉬를 삽입, 패딩 등 최종 처리를하여 해시계산 완료

4. 비트 연산을 이용한 HashValue 전처리

  • hash 값이 음수일 경우 양수로 변환하기위한 작업
  • 1byte = 8bit
  • 8bit의 10진수 표현범위 = -128~127
  • 1111111(2진수) = -1(10진수)
  • 2^7자리 비트는 양(0)/음수(1) 판별 하는 SIGN 비트 (음수가 없는 UNSIGNED가 아님)
  • 0xFF = 255(10진수)
  • Int형 정수 타입(32Bit)으로 255를 표기하면 0000 0000 0000 0000 0000 0000 1111 1111
  • 그래서 바이트 데이터(8bit)와 AND연산 처리 시에 10진수 형태 (0~255)로 바꿀수가 있다.

ex)
-1 & 0xFF(255)
(0xFF) 0000 0000 0000 0000 0000 0000 1111 1111
(AND연산) &
(-1) 1111 1111 1111 1111 1111 1111 1111 1111
|---------------------------------------------------------------|
(결과) = 0000 0000 0000 0000 0000 0000 1111 1111

🔒활용

  1. 로그인 시에 최초로 발생한 salt 값을 DB에 유저정보와 함께 저장해 둠
  2. salt값은 source가 같아도 만들때마다 다른값이 반환되므로(random) 최초에 저장된 salt값이 아니면 똑같은 HashValue에 도달 불가능
  3. 회원가입 시 "PlainText 형태의 비밀번호 + 해당 Salt값"을 SHA256 알고리즘으로 암호화한 CipherText 비밀번호를 DB에 저장
  4. 클라이언트가 로그인 요청 시 서버 내부에서 식별자를 이용해 DB에 있는 "Salt"값을 조회
  5. "클라이언트가 입력한 PlainText 비밀번호 + DB조회 Salt값" 을 SHA256알고리즘으로 암호화한 후, DB에 저장되어있는 암호화된 비밀번호와 비교해서 일치하면 유효한 로그인으로 서비스를 제공

🔒검증

서버 로그인 서비스 API의 일부 코드
1) DB에 저장된 Salt 조회,
2) 사용자가 입력한 PlainText를 Salt와 같이 암호화 후,
3) DB저장 비밀번호와 비교하는 순서

1. 회원가입 API 요청 성공

1-1) 회원가입 요청

1-2) 서버 로그 확인

1-3) DB저장 정보 확인

2. 로그인 API 요청 성공

2-1) 로그인 요청

2-2) 서버 로그 확인: DB와 똑같은 비밀번호로 암호화된 CipherText가 출력됨

3. 직접 검증

0개의 댓글