ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SALT 암호화
    CS/웹 보안 2025. 3. 17. 07:27

    Salt 암호화란?

    Salt 암호화는 비밀번호 해싱(Password Hashing) 과정에서 추가적인 보안 강화를 위해 임의의 데이터(Salt) 를 추가하는 기법입니다. 단순 해싱만 수행하면 동일한 비밀번호는 항상 같은 해시 값이 생성되지만, Salt를 사용하면 같은 비밀번호라도 서로 다른 해시 값을 만들 수 있습니다.

     

    1. 왜 Salt가 필요한가?

    비밀번호를 안전하게 저장하기 위해 해시 함수를 사용하지만, 단순 해싱에는 몇 가지 보안 문제가 있습니다.

    (1) 무차별 대입 공격(Brute Force Attack)

    • 공격자가 가능한 모든 비밀번호를 해싱하여 미리 저장한 후, 이 값을 비교하여 비밀번호를 찾는 방법.
    • 해시 함수만 사용하면 공격자는 사전(Dictionary) 공격을 통해 쉽게 비밀번호를 알아낼 수 있음.

    (2) 레인보우 테이블 공격(Rainbow Table Attack)

    • 해시 값을 미리 계산한 거대한 테이블을 만들어놓고, 이를 통해 비밀번호를 역추적하는 기법.
    • 미리 만들어진 해시 값을 이용하므로 공격 속도가 매우 빠름.
    • 같은 비밀번호라면 항상 같은 해시 값이 나오기 때문에 쉽게 크랙 가능.

    해결책: Salt를 추가하여 해시 값을 다르게 만들면, 레인보우 테이블을 사용한 공격이 무력화됨.


    4. Salt 사용 시 고려해야 할 사항

    1. Salt 길이는 충분히 길어야 함
      • 최소 16바이트(128비트) 이상 추천.
      • 짧은 Salt는 보안성이 낮아질 수 있음.
    2. Salt는 랜덤하게 생성해야 함
      • 정적(Static) Salt를 사용하면 보안성이 낮아짐.
      • os.urandom() 또는 secrets.token_bytes()를 사용하여 안전한 난수를 생성해야 함.
    3. 각 사용자마다 다른 Salt 사용
      • 모든 사용자가 동일한 Salt를 사용하면 보안성이 떨어짐.
      • 개별 사용자의 비밀번호마다 새로운 Salt를 생성해야 함.
    4. 보안성을 높이려면 KDF(PBKDF2, bcrypt, Argon2) 사용
      • 단순 해싱보다 강력한 보안 제공.
      • 반복 연산을 통해 공격자가 해싱을 빠르게 수행하는 것을 방지.

     

    1. SHA-256 + Salt 적용 예시

    기본적인 SHA-256 해싱과 Salt를 적용하는 방법입니다.

    예제 코드 (SHA-256 + Salt)

    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.util.Base64;
    
    public class SaltedHashExample {
        // 랜덤 Salt 생성
        public static byte[] generateSalt() {
            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[16]; // 16바이트 Salt
            random.nextBytes(salt);
            return salt;
        }
    
        // SHA-256을 사용한 비밀번호 해싱
        public static String hashPassword(String password, byte[] salt) throws NoSuchAlgorithmException {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(salt); // Salt 추가
            byte[] hashedPassword = md.digest(password.getBytes());
    
            // Base64로 인코딩하여 문자열로 변환
            return Base64.getEncoder().encodeToString(hashedPassword);
        }
    
        public static void main(String[] args) throws NoSuchAlgorithmException {
            String password = "securepassword";
    
            // Salt 생성
            byte[] salt = generateSalt();
            System.out.println("Salt: " + Base64.getEncoder().encodeToString(salt));
    
            // 비밀번호 해싱
            String hashedPassword = hashPassword(password, salt);
            System.out.println("Hashed Password: " + hashedPassword);
        }
    }
    • SecureRandom을 사용해 16바이트 길이의 Salt를 생성.
    • MessageDigest를 활용해 SHA-256 해시 알고리즘을 적용.
    • Base64.getEncoder().encodeToString()을 사용해 해시 값을 문자열로 변환.

    하지만! SHA-256은 반복 연산이 없기 때문에 해킹이 쉬운 편입니다.
    PBKDF2 또는 BCrypt 같은 더 강력한 알고리즘을 사용하는 것이 좋습니다.

     

     

    2. PBKDF2 적용 예시

    PBKDF2는 100,000번 이상의 반복 연산을 통해 보안을 강화하는 KDF(Key Derivation Function)입니다.

    예제 코드 (PBKDF2 + Salt)

    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.spec.InvalidKeySpecException;
    import java.util.Base64;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    
    public class PBKDF2Example {
        // 랜덤 Salt 생성
        public static byte[] generateSalt() {
            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[16]; // 16바이트 Salt
            random.nextBytes(salt);
            return salt;
        }
    
        // PBKDF2를 사용한 비밀번호 해싱
        public static String hashPassword(String password, byte[] salt) 
                throws NoSuchAlgorithmException, InvalidKeySpecException {
            int iterations = 100000; // 반복 횟수 (보안성 ↑)
            int keyLength = 256; // 256비트 해시 생성
    
            PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keyLength);
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            byte[] hash = skf.generateSecret(spec).getEncoded();
    
            return Base64.getEncoder().encodeToString(hash);
        }
    
        public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
            String password = "securepassword";
    
            // Salt 생성
            byte[] salt = generateSalt();
            System.out.println("Salt: " + Base64.getEncoder().encodeToString(salt));
    
            // 비밀번호 해싱
            String hashedPassword = hashPassword(password, salt);
            System.out.println("Hashed Password: " + hashedPassword);
        }
    }
    • PBKDF2WithHmacSHA256을 사용하여 100,000번 반복 연산을 수행.
    • SecretKeyFactory를 활용해 비밀번호 해싱.
    • Base64.getEncoder().encodeToString()을 사용해 해시 값을 문자열로 변환.

    PBKDF2는 보안성이 뛰어나지만 연산 비용이 상대적으로 높습니다.
    따라서 BCrypt를 사용하는 것이 더 효과적일 수 있습니다.

     

     

    3. BCrypt 적용 예시

    BCrypt는 내장된 Salt 자동 관리 기능을 제공하며, 가변적인 연산 비용(Work Factor) 을 지원하여 보안성이 뛰어납니다.

    예제 코드 (BCrypt)

    import org.mindrot.jbcrypt.BCrypt;
    
    public class BCryptExample {
        public static void main(String[] args) {
            String password = "securepassword";
    
            // 비밀번호 해싱 (Salt 자동 포함)
            String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt(12)); // Work factor = 12
            System.out.println("Hashed Password: " + hashedPassword);
    
            // 비밀번호 검증
            boolean isMatch = BCrypt.checkpw(password, hashedPassword);
            System.out.println("Password Match: " + isMatch);
        }
    }
    • BCrypt.gensalt(12): Salt를 자동 생성하고 Work Factor(연산 비용) 을 12로 설정.
    • BCrypt.hashpw(password, salt): 자동으로 Salt를 포함한 해시 생성.
    • BCrypt.checkpw(password, hashedPassword): 사용자가 입력한 비밀번호가 일치하는지 검증.

    BCrypt의 장점

    - Salt 자동 관리 → 따로 Salt를 저장할 필요 없음.
    - Work Factor 설정 가능 → 높은 값일수록 공격이 어려워짐.
    - 적응형 해싱 → 시간이 지날수록 연산 비용을 증가시켜 보안성을 유지.

    BCrypt는 보안성이 뛰어나기 때문에 비밀번호 해싱에 가장 추천되는 방법입니다.

    'CS > 웹 보안' 카테고리의 다른 글

    SSL, HTTPS, SSH  (0) 2025.03.28
    로그인 인증 방식 - 쿠키&세션, JWT토큰  (0) 2024.07.04
Designed by Tistory.