Server/Security

Salt Hash를 활용한 패스워드 암호화

suee97 2025. 5. 7. 03:42

유저 패스워드 저장 방식

@PostMapping("/join")
public String join(User user) {    
    userService.join(user);
    return "redirect:/";
}

 

패스워드 암호화를 하지 않고 데이터베이스에 그대로 저장했다.

 

패스워드를 암호화하지 않고 저장하는 것의 문제점

1. 해커가 DB서버에 접근해 데이터를 탈취했을 때 사용자 이메일과 패스워드 모두를 알게 된다.

➤ 보통의 사용자는 여러 서비스에 동일한 이메일과 패스워드를 사용한다.

➤ 즉, DB 서버를 운영하는 서비스뿐만 아니라, 다양한 서비스에 탈취한 계정으로 접속해 악의적인 행위를 할 수 있다.

 

2. 관리자에 의한 유출

DB 서버 접근 권한을 가진 관리자가 계정을 유출시킬 수 있다.

 

이러한 이유로 비밀번호는 평문 그대로를 저장하는 것이 아니라, 암호화해서 저장을 해야 한다.

 

 

패스워드 암호화 방식: 해싱

평문을 해시 함수에 넣어 해시 값을 저장하는 방식으로 암호화할 수 있다.

로그인 시에는 입력받은 패스워드를 같은 해시 알고리즘을 활용해 해시 값을 구하고, 이것을 DB에 있는 패스워드와 비교하는 방식으로 할 수 있다.

또한, 해싱된 값을 활용해 역으로 입력 값을 추출하는 것은 불가능에 가깝기 때문에 안전하다고 볼 수 있다.

public String sha256(String input) throws NoSuchAlgorithmException {
    // 1. SHA-256 알고리즘을 수행하는 MessageDigest 객체 생성
    MessageDigest md = MessageDigest.getInstance("SHA-256");

    // 2. 입력 문자열을 바이트로 변환해 해시 계산에 공급
    byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));

    // 3. 결과 바이트 배열을 16진수 문자열로 변환
    StringBuilder hexString = new StringBuilder();
    for (byte b : hashBytes) {
       hexString.append(String.format("%02x", b));
    }

    return hexString.toString();
}
public void join(User user) throws NoSuchAlgorithmException {
    String newPassword = sha256(user.getPassword());
    user.setPassword(newPassword);
    userDao.join(user);
}

 

해싱된 비밀번호가 저장된 모습

 

 

 

그러나, 이 방식도 문제가 있다.

해시 알고리즘은 주로 SHA 계열을 사용한다.

➤ 이 해시 알고리즘에 일반적인 비밀번호를 입력값으로 넣어서 무수히 많은 결과를 만든 테이블이 존재한다. (Rainbow table)

➤ 입력 값 - 해시 값으로 매핑 된 테이블에서 평문을 찾는다.

 

 

 

SHA 계열의 해시 알고리즘이 빠른 속도를 가지고 있고, 컴퓨터가 빨라질수록 해싱 속도가 빨라진다는 점에서 무작위로 입력값을 넣고 rainbow table을 더 쉽게 만들게 한다.

또한, 인간이 기억할 수 있는 비밀번호는 길이의 한계가 있기 때문에 해싱 속도는 하드웨어의 발전 속도에 따라 빨라지기만 한다는 점에서 문제가 있다.

 

 

 

해싱 암호화 단점 보완: Salt Hash

평문 패스워드에 사용자별로 특정 문자열(salt)을 붙이고, 이것을 해싱하여 암호화하는 방식이다.

예를 들어, 비밀번호가 1234이고 salt가 qwer 이면 1234qwer와 같은 방식으로 새로운 문자열을 생성하고, 이것을 해싱하는 방식이다.

salt가 붙은 비밀번호 조합은 너무 다양하고 무작위적이기 때문에, 일반적인 rainbow table에는 포함되어 있지 않다. 따라서 해커는 그 조합을 직접 계산해보는 brute-force 방식을 사용해야 한다

또한 사용자별로 부여되는 salt값이 다르기 때문에, 이렇게 해서 계정 하나를 해킹했다고 하더라도 다른 계정을 해킹할 수 있는 것은 아니다.

 

 

salt가 저장된 DB와 패스워드가 저장된 DB가 같고, 그 DB가 해킹당한다면 brute force가 쉬워진다.

하지만 두 개의 DB에 나눈다면 이에 따른 운영 비용이 증가하기 때문에 효율성과 보안의 균형을 잘 고려해서 선택해야 한다.

 

 

Salt Hash의 단점

사용자별로 salt값이 주어진다고 했는데, 이 정보가 유출되면 brute force 공격을 더욱 쉽게 만들 수 있다.

또한 DB서버의 모든 계정의 비밀번호 해시 값을 탈취한 뒤, brute force 방식으로 특정 계정만을 위한 rainbow table을 만드는 것이 불가능한 것은 아니다.

 

 

Salt Hash의 단점 보완

무작위 값으로 해시 값을 맞추는 brute force 방식은 빠른 연산 속도가 뒷받침되기 때문에 가능하다.

따라서 해싱 연산 비용을 늘리는 Key Stretching 방식으로 brute force 공격을 지연할 수 있다.

즉, brute force 공격으로 해킹해서 얻는 이득보다 공격으로 소요되는 시간, 노력, 인내, 비용를 더 높이는 것이다.

하지만 이러한 방식을 사용하더라도 앞서 말한 비용을 다 감수하고서라도 해킹을 할 수 있음을 인지하고 2차 인증과 같은 추가적인 보안을 구축해야 한다.

 

 

'Server > Security' 카테고리의 다른 글

Argon2id 파라미터 조정을 통한 해싱 지연  (0) 2025.05.26