BCrypt Encode

dropKick·2020년 9월 25일
0

스프링 프레임워크

목록 보기
5/13

Spring security를 사용하는데 UserDetailService에 의해 패스워드를 저장할 때
이 인코딩 방식을 기본적으로 추천하고 사용하는데 이게 뭘까?

암호화

일단 패스워드 암호화는 일반적으로 양방향과 단방향으로 구별 가능하다.
하지만 양방향의 경우 사용자의 편의성이나 속도가 중요한 부분에서 키의 문제로 그다지 사용하지 않고, 단반향 암호화인 해시를 주로 사용한다.

하지만 해시의 경우 애초에 해시 테이블을 통한 빠른 데이터 검색과 매칭을 목적으로 만들어졌기때문에 빠른 속도라는 장점이자 단점을 가지고 있다.
이는 해시 함수를 이용한 암호화 패턴인 해시 테이블이 존재때문인데 Brute Force 공격은 MD5의 경우 1초당 무려 56억개의 대입이 가능하고, 사용자는 패스워드 암호화 과정에서 0.1초와 1초의 차이를 별로 신경쓰지 않기에 오히려 공격자에게 유리한 상황이 되버린다.

또한 동일한 문자열은 동일한 해시 테이블을 가진다면 무지막지하게 많은 문자열을 이용하여 매칭해보는 레인보우 테이블과 해시 충돌에 따른 위험성이 존재한다.

이를 해결하는 방법은 해시 충돌 가능성을 줄이기위해 길이를 무지막지하게 늘리거나, 임의의 문자열을 첨가하여 아예 해시 결과가 달라지게 만드는 방법이 있다.

그 중 무지막지한 길이 늘리기 방법은 SHA 알고리즘에서 사용하는데 SHA-1 방식의 경우
이미 해시 충돌이 발견되어 사장되었고, SHA-2 방식이 사용 중이며 SHA-256이나 SHA-512 방식의 경우 똑같이 해시 충돌이 발생할 수 있지만
2^256, 2^512 라는 무지막지한 길이를 통해 해시 충돌의 가능성은 거의 없다.

BCrypt

그렇다면 임의의 문자열을 첨가하는 것은 뭘까?
Salt라는 임의의 문자열을 첨가하는 것 Salting이라고 하는 방식으로 BCrypt 암호화가 사용하는 방식이다.
해시는 해시 함수를 통해 문자열을 지정된 길이만큼 변환시키기 때문에 단 하나의 문자열만 달라지더라도 전혀 다른 값이 나오고 이는 레인보우 테이블이나 Brute Force 공격에 대해 상대적으로 안전하다.

// Spring Security 
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

스프링 시큐리티에서는 BCryptPasswordEncoder라는 방식으로 구현되어 있으며 Salt의 강도를 조절할 수 있다.

public String encode(CharSequence rawPassword) {
		if (rawPassword == null) {
			throw new IllegalArgumentException("rawPassword cannot be null");
		}

		String salt;
		if (strength > 0) {
			if (random != null) {
				salt = BCrypt.gensalt(strength, random);
			}
			else {
				salt = BCrypt.gensalt(strength);
			}
		}
		else {
			salt = BCrypt.gensalt();
		}
		return BCrypt.hashpw(rawPassword.toString(), salt);

그리고 구현체를 확인 시 String salt라는 랜덤한 문자열을 암호화 과정에서 같이 집어넣는 것을 확인할 수 있다.

결론적으로 BCrypt는 Salt를 이용하여 가장 간단하면서 효율적으로 패스워드 암호화를 지원할 수 있는 방법이다.

0개의 댓글