17주차 - Spring(20) 암호화를 해보자

2022. 10. 24. 19:07Spring framwork

이번의 목표

01. 암호화를 해보자.

02. 암호화의 특징을 알아보자.

03. 암호화된 패스워드를 검증해보자.


01. 암호화를 해보자.

지난 시간에 Spring Security Web을 설치했으니 이제 암호화를 직접 해보겠습니다.

암호화를 하기 위한 가장 기본 객체는 BCryptPasswordEncoder 입니다. 생성 코드 예시는 아래와 같습니다.

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

암호화는 BCryptPasswordEncoder 객체의 encode() 메서드를 이용해 가능합니다.

회원가입을 하며 비밀번호를 암호화하는 세가지의 예시를 보겠습니다.

암호화 하는 코드 예시는 아래와 같습니다.

String cipherPassword = encoder.encode(password);

위의 코드를 이용하여 회원가입을 하고 그때 암호화된 결과의 결과는 아래와 같습니다.

 

첫번째)

암호화 전 : 1111
암호화 후 : $2a$10$VCxfLQg5ZVNMUgabF53DsOsHoC/ygRjiKRaB2XXBg6zh.dzOP0oM6
암호화 후 길이 : 60

 

두번째)

암호화 전 : 1111
암호화 후 : $2a$10$51M5tri6ENB6oK30zR/TJeNFUpocNRSSpkDl5QVfR/SmmECSHDi1y
암호화 후 길이 : 60

 

세번째)

암호화 전 : 11111111
암호화 후 : $2a$10$2jEEvH.L./0/aB9U6yjxyewZh03y.iZqv9OE0IB9F2.1jLwjlwxuG
암호화 후 길이 : 60

 

02. 암호화의 특징을 알아보자.

암호화의 특징을 알기 위해서 위의 세가지 예제에 대해 다시 보겠습니다.

첫번째)
암호화 전 : 1111
암호화 후 : $2a$10$VCxfLQg5ZVNMUgabF53DsOsHoC/ygRjiKRaB2XXBg6zh.dzOP0oM6
암호화 후 길이 : 60

두번째)
암호화 전 : 1111
암호화 후 : $2a$10$51M5tri6ENB6oK30zR/TJeNFUpocNRSSpkDl5QVfR/SmmECSHDi1y
암호화 후 길이 : 60

세번째)
암호화 전 : 11111111
암호화 후 : $2a$10$2jEEvH.L./0/aB9U6yjxyewZh03y.iZqv9OE0IB9F2.1jLwjlwxuG
암호화 후 길이 : 60

첫번째와 두번째의 결과를 비교하며 알 수 있는 것은 패스워드가 같아도 암호화 후에는 서로 다른 패스워드를 갖는다는 것입니다. 이때 암호문은 평문과 salt를 더해서 암호화 알고리즘에 적용후 암호화 과정을 거쳐 암호문이 생성됩니다.

※salt : random값

 

다음으로 두번째와 세번째의 결과를 비교하며 알 수 있는 것은 단방향 암호화의 알고리즘이 서로 같다면 길이는 동일하다는 것입니다. 두번째의 암호화 이전 비밀번호는 1111 로 4글자이고, 세번째의 비밀번호는 11111111로 8글자임에도 불구하고 암호화된 패스워드는 둘다 60의 길이를 가지고 있습니다.

 

03. 암호화된 패스워드를 검증해보자.

이렇게 암호화된 패스워드는 기존의 equals로 검증할 수 없습니다.

암호화된 비밀번호와 사용자가 입력하는 비밀번호를 검증하기 위해서는 BCryptPasswordEncoder의 matches() 메서드를 사용해야합니다. 사용 예시는 아래와 같습니다.

encoder.matches(일반 패스워드, 암호화 패스워드);

사용자가 입력한 패스워드와 데이터베이스에 저장된 암호화 패스워드를 위와같이 입력하면 boolean형태의 값을 반환합니다. 이를 이용하여 값을 검증할 수 있습니다.

 

이를 응용한 코드 예제 입니다.

01. 페이지 코드
02. 컨트롤러 코드
03. 서비스 코드

 

01. 페이지 코드

<body>

<c:choose>
<c:when test="${not empty sessionScope }">
<script type="text/javascript">
alert("이미 로그인 되어있습니다.")
location.href='index';
</script>
</c:when>
<c:otherwise>
	<c:if test="${msg ne null }">
	<script type="text/javascript">
	alert("${msg}")
	</script>
	</c:if>

<h3>로그인 페이지</h3>
<form action="login" method="post">
	<input type="text" name="id" placeholder="아이디"><br>
	<input type="password" name="cipherPassword" placeholder="비밀번호"><br>
	<input type="submit" value="로그인">
	<input type="button" value="취소" onclick="location.href='index'">
</form>


</c:otherwise>
</c:choose>
</body>

02. 컨트롤러 코드

	@GetMapping("member/login")
	public void login() {}
	
	@PostMapping("member/login")
	public String logind(MemberDTO dto, Model model) {
		String result = service.login(dto);
		model.addAttribute("msg", result);
		if(result.equals("로그인 성공")) {
			return "member/index";
		}
		model.addAttribute("msg", result);
		return "member/login";
	}

03. 서비스 코드

	public String login(MemberDTO dto) {
		MemberDTO data = dao.selectId(dto.getId());
		
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		
		//rawPassword = 평문 / encodedPassword = 암호화
		if(data == null || (encoder.matches(dto.getCipherPassword(), data.getCipherPassword())==false) ) {
			return "로그인 실패";
		}
		session.setAttribute("id", data.getId());
		session.setAttribute("name", data.getName());
		session.setAttribute("email", data.getEmail());
		return "로그인 성공";
	}