Kim VamPa

[Spring][Spring Security]BCryptPasswordEncoder란? 본문

공부/스프링

[Spring][Spring Security]BCryptPasswordEncoder란?

Kim VamPa 2021. 1. 18. 21:45
728x90
반응형

목표

  • BCryptPasswordEncoder가 무엇인지 이해합니다.
  • BCryptPasswordEncoder의 메서드 구성을 공부합니다.
  • BCryptPasswordEncoder의 메서드를 직접 사용해봅니다.

 

 

순서

1. BCryptPasswordEncoder란?

2. BCryptPasswordEncoder 메서드 구성

3. BCryptPasswordEncoder 사용방법

4. 실습

 

 

1. BCryptPasswordEncoder란?

 스프링 시큐리티(Spring Seurity) 프레임워크에서 제공하는 클래스 중 하나로 비밀번호를 암호화하는 데 사용할 수 있는 메서드를 가진 클래스입니다.

 스프링 시큐리티(Spring Security)란 자바 서버 개발을 위해 필요로 한 인증, 권한 부여 및 기타 보안 기능을 제공하는 프레임워크(클래스와 인터페이스 모임)입니다.

 

- BCryptPasswordEncoder는 BCrypt 해싱 함수(BCrypt hashing function)를 사용해서 비밀번호를 인코딩해주는 메서드와 사용자의 의해 제출된 비밀번호와 저장소에 저장되어 있는 비밀번호의 일치 여부를 확인해주는 메서드를 제공합니다.

- PasswordEncoder 인터페이스를 구현한 클래스입니다.

- 생성자의 인자 값(verstion, strength, SecureRandom instance)을 통해서 해시의 강도를 조절할 수 있습니다.

 

BCryptPasswordEncoder는 위에서 언급했듯이 비밀번호를 암호화하는 데 사용할 수 있는 메서드를 제공합니다. 기본적으로 웹 개발함에 있어서 사용자의 비밀번호를 데이터베이스에 저장하게 됩니다. 허가되지 않은 사용자가 접근하지 못하도록 기본적인 보안이 되어 있을 것입니다. 하지만 기본적 보안이 되어 있더라도, 만약 그 보안이 뚫리게 된다면 비밀번호 데이터는 무방비하게  노출됩니다. 이런 경우를 대비해 BCryptPasswordEncoder에서 제공하는 메서드를 활용하여 비밀번호를 암호화 함으로써 비밀번호 데이터가 노출되더라도 확인하기 어렵도록 만들어 줄 수 있습니다.

 

 

2. 메서드 구성

 BCryptPasswordEncoder는 스프링 시큐리티 5.4.2부터는 3개의 메서드, 그 이전 버전은 2개의 메서드를 가집니다. 공통적으로 encdoe(), matchers() 메서드에 upgradeEncoding() 메서드가 추가되었습니다.

 

그림 1

 

encode(java.lang.CharSequence rawPassword)

  • 패스워드를 암호화해주는 메서드입니다. encde() 메서드는 SHA-1, 8바이트로 결합된 해쉬, 랜덤 하게 생성된 솔트(salt)를 지원합니다. 
  • 매개변수는 java.lang.CharSequence타입의 데이터를 입력해주면 됩니다. (CharSequence를 구현하고 있는 java.lang의 클래스는 String, StringBuffer, StringBuilder가 있습니다.)
  • 반환 타입은 String 타입입니다.
  • 똑같은 비밀번호를 해당 메서드를 통하여 인코딩하더라도 매번 다른 인코딩 된 문자열을 반환합니다.

 

matchers(java.lang.CharSequence rawPassword, java.lang.String encodePassword)

  • 제출된 인코딩 되지 않은 패스워드(일치 여부를 확인하고자 하는 패스워드)와 인코딩 된 패스워드의 일치 여부를 확인해줍니다.
  • 첫 번째 매개변수는 일치 여부를 확인하고자 하는 인코딩 되지 않은 패스워드를 두 번째 매개변수는 인코딩 된 패스워드를 입력합니다.
  • 반환 타입은 boolean입니다.

 

upgradeEncoding(java.lang.String encodePassword)

  • 더 나은 보안을 위해서 인코딩 된 암호를 다시 한번 더 인코딩해야 하는 경우에 사용합니다.
  • 매개변수는 인코딩 필요 여부를 확인하고자 하는 인코딩 된 패스워드(String 타입)를 입력합니다.
  • 반환 타입은 인코딩이 필요한 경우 true를, 필요하지 않은 경우는 false를 입력합니다.
  • 기본 구현에는 항상 flase를 반환합니다.
  • encde() 메서드를 통해서 암 호환된 패스워드들은 upgradeEncoding()을 사용했을 때 모드 기본적으로 false를 반환합니다.
  • 따라서 개인적으로 생각해보았을 때 해당 메서드는 오버라이딩하여 더 강력한 해시를 해야 할지의 기준을 정한 뒤 로직 처리하여 활용할 수 있을 거 같습니다.

 

3. 사용방법

 스프링 시큐리티의 클래스 중 하나이기 때문에 스프링 시큐리티 라이브러리 추가와 기본적 설정이 필요합니다. 전체적인 과정은 다음과 같습니다.

 

1. 스프링 시큐리티 pom.xml 추가

2. 스프링 시큐리티 기본 설정(web.xml 설정, securi-context.xml 파일 추가 및 BCryptPasswordEncoder 빈 등록)

 

1. 스프링 시큐리티 pom.xml 추가

 pom.xml에 아래와 같이 3가지를 추가해줍니다. 버전의 경우 자신이 원하는 버전을 입력하시면 됩니다. (저의 경우 upgradeEncdoding() 메서드를 사용해보고 싶어서 5.4.2로 설정하였습니다.)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
        <!-- security -->
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.4.2</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>5.4.2</version>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>5.4.2</version>
        </dependency>    
 
cs

 

그림 2

 

 

2. 스프링 시큐리티 기본 설정

 기존에 있던 servlet-context.xml에 security namespace를 추가하여 설정해도 됩니다. 하지만 spring security와 관련된 빈과 설정을 따로 관리하기 위해서 security-context.xml 파일을 새로 만들어서 설정하겠습니다.

 

먼저 servlet-context.xml파일이 있는 경로에 'Spring Bean Configuration File'을 통해서 'security-context'이름의 파일을 'benas'와 'security' namespaces를 추가 해준 뒤 생성합니다.

* security namespace의 경우 버전이 적히지 않은 것을 선택해줍니다.

 

그림 3

 

그림 4

 

그림 5

 

그림 6

 

 생성한 파일에 BCryptPasswordEncoder를 빈으로 등록하기 위해 아래의 코드를 추가해줍니다.

 

1
2
3
 
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
 
cs

 

그림 7

 

 web.xml에서 servlet-context.xml의 경로가 적힌 태그 안에 줄 바꿈을 하여 동일하게 Security-context.xml파일의 위치를 삽입해줍니다. 해당 과정을 생략하면 스프링에서 security-context.xml을 인식하지 못합니다.

 

그림 8 추가 전

 

그림 9 추가 후

 

이로써 BCryptPasswordEncoder를 사용하기 위한 기본적인 설정이 끝났습니다.

 

 

4. 실습

 위의 설정을 바탕으로 BCryptPasswordEncoder의 메서드를 직접 사용해보겠습니다. MVC 웹 프로젝트를 처음 생성했을 때 기본적으로 존재하는 HomeController.java를 활용하겠습니다.

 

 먼저 @Autowired를 사용해서 BCryptPasswordEncoder를 의존성 주입시켜줍니다.

 

1
2
3
4
 
    @Autowired
    BCryptPasswordEncoder passwordEncoder;
 

 

그림 10

 

security 메서드만을 테스트하기 위한 url 맵핑 메서드를 추가하였습니다. 

 

1
2
3
4
5
6
7
 
    @RequestMapping(value = "/secuTest", method = RequestMethod.GET)
    public void secuTest() {
        
        
    }
 
cs

 

그림 11

 

 아래와 같이 테스트를 위한 코드를 추가하였습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
    @RequestMapping(value = "/secuTest", method = RequestMethod.GET)
    public void secuTest() {
        
        String rawPassword = "vam123";                //인코딩 전 메서드
        String encdoePassword1;                        // 인코딩된 메서드
        String encdoePassword2;                        // 똑같은 비밀번호 데이터를 encdoe()메서드를 사용했을 때 동일한 인코딩된 값이 나오는지 확인하기 위해 추가
        
        encdoePassword1 = passwordEncoder.encode(rawPassword);
        encdoePassword2 = passwordEncoder.encode(rawPassword);
        
        // 인코딩된 패스워드 출력
        System.out.println("encdoePassword1 : " +encdoePassword1);
        System.out.println(" encdoePassword2 : " + encdoePassword2);
        
        String truePassowrd = "vam123";
        String falsePassword = "asdfjlasf";
        
        System.out.println("truePassword verify : " + passwordEncoder.matches(truePassowrd, encdoePassword1));
        System.out.println("falsePassword verify : " + passwordEncoder.matches(falsePassword, encdoePassword1));    
    
    }
 
cs

 

그림 12

서버를 실행하여 해당 url 메서드를 호출한 결과입니다. 

 

그림 13

 

 결과를 보면 분명 같은 rawPassword 변수의 값을  endcode() 메서드를 사용하여 인코딩하였음에도 서로 다른 값이 반환 된 것을 볼 수 있습니다.(encodePassword1!= encdoePassword2)

 

 truePassword 변수에는 일치하는 값을 대입하였고, falsePassword 변수에는 일치하지 않는 값을 대입하였습니다. 해당 변수들을 사용해서 인코딩 된 비밀번호와의 일치 여부를 확인하기 위해서 matches() 메서드를 활용하였고 그 결과로 일치하는 값을 가진 truePassword 변수를 사용했을 경우에는 true를, 일치하지 않는 값을 가진 falsePassword 변수를 사용했을 경우는 false를 반환한 것을 알 수 있습니다. 

 

 

REFERENCE

 

 

DATE

  • 2021.01.18
728x90
반응형
Comments