개(발)린이
Spring(암호화) 본문
오늘 할것은 암호화이다.
DB에 패스워드를 저장할 때 그냥 저장하면 보안에 취약하기 때문에 암호화를 해서 저장하는데
이전 수업땐 sha-512를 이용해 암호화하는걸 배웠다.
근데 sha-512는 똑같은 비밀번호를 작성하면 똑같은 문자로 암호화 되기 때문에 보안에 문제가된다.
이번에 사용할 암호화는 Bcrypt 암호화이다.
우선 평문상태의 pw는 DB상 이렇게 나와있다
이전 sha512 사용시 순서는
비밀번호 담긴 요청 -> 필터 -> Wrapper(암호화) -> Servlet 순서로 암호화 상태로 DB에 저장시켰다.
이번엔 좀 다른 순서로 접근한다.
우선 Bcrypt암호화를 사용하면
ex) 1234 -> abcd
1234 -> sdfe
이런식으로 누를때마다 다르게 암호화가 된다.
그렇다면 이상태로 DB에 저장하면 로그인이 그냥은 안될것이다.
그래서 오늘은 matches라는 메소드를 사용하여 비밀번호가 제대로 조회가 되어서 로그인이 되게끔 만들어 볼거다.
먼저 Bcrypt를 사용하려면 Spring Sequrity 모듈이 필요하다
MVN REPOSITORY에 들어가보자
여기서 1(core), 2(Web), 3(Config)을 추가하면 된다.
core에 들어가보자
자기에게 맞는 버전을 클릭해보자
복사해 pom.xml에 추가해준다.
web과 config도 똑같이 해준다.
<dependencies>
<!-- Spring-security 모듈 추가 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.7.1</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.7.1</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.7.1</version>
</dependency>
본인은 5.7.1로 맞췄으며 pom.xml파일 내부에 dependencies 태그 안에 넣어주면된다.
그후 Spring 폴더안에 새로운 xml파일 생성해준다.
* 밑에는 아무것도 체크안하면된다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-5.7.xsd">
</beans>
spring-security.xml내부 코드이다
<bean>생성되는 코드를 작성해보자
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-5.7.xsd">
<!-- Bcrypt 암호화용 bean 생성 -->
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
//id는 객체 이름 class는 경로이다.
<!-- bean 만들어놓고 사용시 DI(의존성 주입) => Autowired 어노테이션 작성해 사용하면 됨.
</beans>
그후 web.xml로 이동
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring/root-context.xml
classpath:spring/spring-security.xml
</param-value>
</context-param>
하나의 param-value 태그 안에 추가해준다.
다음으로 Service로 이동
@Service//bean 객체 등록 + @Service는 비즈니스 로직을 처리하는 클래스임을 명시
public class MemberServiceImpl implements MemberService{
// 내가 만든걸 상속받는건 POJO에 위배되지 않음.
@Autowired
private MemberDAO dao;
@Autowired // 암호화를 위한 bycrypt 객체 의존성 주입(DI)
private BCryptPasswordEncoder bcrypt;
private Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
// 작동되는지 로그로 확인.
@Override
public Member login(Member inputMember) {
// 전달 받은 비밀번호를 암호화 하여
// DB에서 조회한 비밀번호와 비교( DB에서 비교 X )
// sha 방식 암호화
// A회원 / 비밀번호 1234 -> 암호화 : abcd
// B회원 / 비밀번호 1234 -> 암호화 : abcd(암호화 시 변경된 내용이 같음)
// Bcrypt 암호화 : 암호화 하기 전에 salt를 추가하여 변형된 상태로 암호화를 진행
// A회원 / 비밀번호 1234 -> 암호화 : abcd
// B회원 / 비밀번호 1234 -> 암호화 : !sd2
logger.debug( inputMember.getMemberPw() + "/" + bcrypt.encode(inputMember.getMemberPw()));
logger.debug( inputMember.getMemberPw() + "/" + bcrypt.encode(inputMember.getMemberPw()));
logger.debug( inputMember.getMemberPw() + "/" + bcrypt.encode(inputMember.getMemberPw()));
logger.debug( inputMember.getMemberPw() + "/" + bcrypt.encode(inputMember.getMemberPw()));
logger.debug( inputMember.getMemberPw() + "/" + bcrypt.encode(inputMember.getMemberPw()));
Member loginMember = dao.login(inputMember);
return loginMember;
}
}
Bcrypt는 매번 암호화 되는 비밀번호가 달라서 DB에서 직접 비교불가
대신 Bcrypt 암호화를 지원하는 객체가 이를 비교하는 기능 (메소드) 가지고 있어서 이를 활용한다.
서버를 실행해서 로그를 확인해보자. 만약 톰캣 에러가 뜬다면 서버 clean후에 다시 실행해보면 될것이다.
콘솔창을 확인해보면 pass01! 이라는 패스워드가 5개의 로그에 모두 다르게 나온걸 볼 수 있다.
정상적으로 나오는 걸 봤으니 이제 비교하는 기능을 구현해보자
원리는 DB에서 가져온 값과 입력한 값을 Service 클래스에서 비교하는것이다.
우선 member-mapper.xml의 sql문을 수정한다
<select id="login" parameterType="member" resultMap="member_rm">
SELECT MEMBER_NO,MEMBER_EMAIL,MEMBER_NICK ,MEMBER_TEL,
MEMBER_ADDR, PROFILE_IMG,
TO_CHAR( ENROLL_DT, 'YYYY-MM-DD HH24:MI:SS') AS ENROLL_DT, MEMBER_PW
FROM MEMBER_S
WHERE MEMBER_EMAIL = #{memberEmail}
<!-- AND MEMBER_PW = #{memberPw} -->
AND SECESSION_FL = 'N'
</select>
member-mapper.xml에 있는 select문을 수정하였다.
DB에서 비교하는게 아니기 때문에 memberPw단은 주석처리, 그리고 SELECT에 MEMBER_PW를 추가하였다
다시 Service클래스로 돌아와 일치하는 이메일을 가진 회원 정보가 있는지
그리고 비밀번호가 일치하는지 if else 문을 이용하여 작성해준다.
if(loginMember != null){ // 일치하는 이메일을 가진 회원 정보가 있을 경우
// 평문 , DB에서 조회한 암호화된 비번
// => 같으면 true
if(bcrypt.matches(inputMember.getMemberPw(), loginMember.getMemberPw())) {
loginMember.setMemberPw(null); // 비교 끝났으면 비밀번호 지우기(비번은 세션에 올라가면 안된다.)
} else { // 비밀번호가 일치하지 않을 경우
loginMember = null;
}
}
다 되었으면 서버를 실행해서 암호화된 비번을 DB에 저장해보자
로그인 성공이다.
콘솔창을 보면
DB에 저장한 값과는 다른걸 알 수 있다.
SHA-512보다 보안성이 뛰어나다는걸 알수있는 부분이다.
다음시간엔 회원가입기능을 구현해보겠다.
'Spring' 카테고리의 다른 글
Spring(회원 가입 - DB저장) (0) | 2023.04.26 |
---|---|
Spring(회원가입 - 이메일 중복 체크) (0) | 2023.04.26 |
Spring(로그아웃 및 쿠키확인) (0) | 2023.04.26 |
Spring(로그인-3 cookie) (0) | 2023.04.26 |
Spring(로그인-2) (0) | 2023.04.26 |