[Spring Boot] 회원가입, 로그인 비밀번호 암호화(인코딩) 하기 (BCryptPasswordEncoder, Gradle)
회원가입 시 데이터베이스에 등록되는 비밀번호를 암호화 하여
만일의 사태에 무방비하게 노출되는 비밀번호 유출을 막기 위해
데이터베이스에 저장되는 비밀번호를 암호화(인코딩) 하는 것이다.
BCryptPasswordEncoder 란?
스프링 시큐리티(Spring Security) 프레임워크에서 제공하는 클래스 중 하나로 비밀번호를 암호화 하는데 사용할 수 있는 메서드를 가진 클래스
여기서 스프링 시큐리티(Spring Security)란 자바 서버 개발을 위해 필요한
인증, 권한 부여 및 기타 보안 기능을 제공하는 프레임워크 이다.
Gradle 설정
implementation 'org.springframework.boot:spring-boot-starter-security' /* Spring security */
Configuration 설정
package com.vam.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().disable() //cors방지
.csrf().disable() //csrf방지
.formLogin().disable() //기본 로그인 페이지 없애기
.headers().frameOptions().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
- CORS(Cross-origin resource sharing) : 교차 출처 리소스 공유(Cross-origin resource sharing, CORS), 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다. 웹페이지는 교차 출처 이미지, 스타일시트, 스크립트, iframe, 동영상을 자유로이 임베드할 수 있다. 특정한 도메인 간(cross-domain) 요청, 특히 Ajax 요청은 동일-출처 보안 정책에 의해 기본적으로 금지된다.
- CSRF(Cross-site request forgery) : 사이트 간 요청 위조(또는 크로스 사이트 요청 위조, 영어: Cross-site request forgery, CSRF, XSRF)는 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 말한다.
출처 - 위키백과
비밀번호 암호화 하기
PasswordEncoder을 Autowired 해줍니다.
@Autowired
private PasswordEncoder pwEncoder;
//회원가입
@RequestMapping(value = "/join", method = RequestMethod.POST)
public String joinPOST(MemberVO member) throws Exception {
logger.info("join 진입");
String rawPw = "";
String encodePw = "";
rawPw = member.getMemberPw();
encodePw = pwEncoder.encode(rawPw);
member.setMemberPw(encodePw);
//회원가입 서비스 실행
memberService.memberJoin(member);
logger.info("join Service 성공");
return "redirect:/main";
}
위의 코드를 보면 rawPw 와 encodePw 라는 변수 두개가 존재합니다.
rawPw 에는 사용자가 입력한 비밀번호를 저장하고,
encodePw 에는 사용자가 입력한 비밀번호를 암호화 하여 저장하고
Service로 DB에 암호화된 비밀번호를 저장합니다.
/* 로그인 */
@RequestMapping(value = "login.do", method = RequestMethod.POST)
public String loginPOST(HttpServletRequest request, MemberVO member, RedirectAttributes rttr) throws Exception {
HttpSession session = request.getSession();
String rawPw = "";
String encodePw = "";
MemberVO lvo = memberService.memberLogin(member);
if (lvo != null) { // 일치하는 아이디 존재시
rawPw = member.getMemberPw(); // 사용자가 제출한 비밀번호
encodePw = lvo.getMemberPw(); // 데이터베이스에 저장한 인코딩 비밀번호
if (true == pwEncoder.matches(rawPw, encodePw)) { //비밀번호 일치 여부 판단
lvo.setMemberPw(""); // 인코딩된 비밀번호 정보 지움
session.setAttribute("member", lvo); // session에 사용자 정보 저장
return "redirect:/main";
} else {
rttr.addFlashAttribute("result", 0);
return "redirect:/member/login";
}
} else { // 일치하는 아이디가 존재하지 않을 시
rttr.addFlashAttribute("result", 0);
return "redirect:/member/login";
}
}
위의 메서드는 login 페이지에서 들어온 데이터를 객체로 받아와서 로그인 하는 메서드입니다.
lvo 객체가 존재하지 않는다면 RedirectAttributes 의 addFlashAttrivbute 의 메서드를 이용하여
휘발성(?)있는 일시적인 데이터로 "result" 즉, 0의 데이터를 보내 JavaScript에서 해당 페이지에서 로그인 실패에 대한 경고문을 발생시키게 처리하였습니다.
일치하는 아이디 존재 시 각 rawPw 와 encodePw 를 matches하여 true를 반환 받게 되면 로그인이 성공하게 됩니다.
그리고 로그인이 성공하고 비밀번호가 암호화가 되었다 하더라도 굳이 뷰에 노출시키 이유가 없기 때문에 인코딩된 비밀번호 정보도 지운 후
session에 사용자 정보를 저장해줍니다.
이렇게하면 회원가입, 로그인 시 비밀번호 암호화하기에 성공하게 됩니다.!
잘못된 정보 지적 부탁드립니다.