package edu.kh.community.common.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import edu.kh.community.common.wrapper.EncryptWrapper;
// 암호화를 적용해야 되는 요청 : 로그인, 회원가입, 비밀번호 변경, 회원 탈퇴
// 필터가 적용될 url이 여러 개인 경우 : String 배열 초기화 형태 {}로 작성
@WebFilter(filterName = "encryptFilter",
urlPatterns = {"/member/login",
"/member/signUp",
"/member/myPage/changePw",
"/member/myPage/secession"
})
public class EncryptFilter extends HttpFilter implements Filter {
public void init(FilterConfig fConfig) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 비밀번호는 파라미터 -> HttpServletRequest에 담겨 있음
// doFilter 메소드 매개변수는 부모 타입인 ServletRequest
// -> 다운 캐스팅 필요
HttpServletRequest req = (HttpServletRequest)request;
// 파라미터를 다시 세팅하는 방법은 필터에서 불가능함
// -> Servlet의 Wrapper 클래스를 이용해서
// HttpServletRequest의 메소드를 오버라이딩 할 수 있다.
// -> 오버라이딩(재정의)를 통해서 비밀번호 암호화 진행
// wrapper 객체를 생성해서 기존 HttpServletRequest 객체 역할을 대체함
EncryptWrapper wrapper = new EncryptWrapper(req);
// 다음 연결된 필터를 수행(없으면 Servlet으로 이동)
chain.doFilter(wrapper, response);
}
}
package edu.kh.community.common.wrapper;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class EncryptWrapper extends HttpServletRequestWrapper {
// HttpServletRequestWrapper
// - 클라이언트 요청 객체 HttpServletRequest를 오버라이딩 하는 방법을 제공하는 클래스
// 생성자가 작성되어 있으면
// 컴파일러가 기본 생성자를 자동으로 추가 안 함
// -> Wrapper 클래스 생성 시 반드시 HttpServletRequest 객체를 매개변수로 전달해야 한다.
public EncryptWrapper(HttpServletRequest request) {
super(request);
}
// getParameter() 오버라이딩
@Override
public String getParameter(String name) {
// 매개변수 name : input 태그의 name 속성 값
// super.getParameter(name) : 기존 getParameter() 메소드
String value = null;
switch(name) {
case "inputPw" :
case "memberPw" :
value = getSha512( super.getParameter(name) );
break;
// 암호화 되는 경우가 아니라면 기존 getParameter() 메소드 형태를 유지
default : value = super.getParameter(name);
}
return value;
}
// 암호화 메소드(SHA-512 해시 함수)
// 해시 함수 : 어떤 문자열이든 일정한 길이의 무작위 문자열로 변환하는 함수(중복X)
private String getSha512(String pw) {
// 매개변수 pw : 암호화 되기 전 비밀번호
String encryptPw = null; // 암호화된 비밀번호 저장 변수
// 1. 해시 함수를 수행할 객체를 참조할 변수 선언
MessageDigest md = null;
try {
// 2. SHA-512 방식의 해시 함수를 수행할 수 있는 객체를 얻어옴
md = MessageDigest.getInstance("SHA-512");
// 3. md를 이용해 암호화를 진행할 수 있도록 pw를 byte[] 형태로 변환
byte[] bytes = pw.getBytes(Charset.forName("UTF-8"));
// 4. 암호화 수행 -> 암호화 결과가 md 내부에 저장됨
md.update(bytes);
// 5. 암호화된 비밀번호를 encryptPw에 대입
// -> byte[]을 String으로 변환할 필요가 있음
// Base64 : byte코드를 문자열로 변환하는 객체
encryptPw = Base64.getEncoder().encodeToString(md.digest());
System.out.println("암호화 전 : "+ pw);
System.out.println("암호화 후 : " + encryptPw);
} catch(NoSuchAlgorithmException e) {
// SHA-512 해시 함수가 존재하지 않을 때 예외 발생
e.printStackTrace();
}
return encryptPw;
}
}
-- 암호화된 비밀번호로 업데이트
UPDATE MEMBER SET
MEMBER_PW = 'aBN5hiegXlvAovJLipPoPd5LB+xjPrAeu1tcAVg0p5MKGocvo6l825SD+ZMCOcHBFeGB7MnzH31SAnDzYYsSdg==';
-- MEMBER TABLE 비밀번호 컬럼 크기 변경
ALTER TABLE MEMBER
MODIFY MEMBER_PW VARCHAR2(100);
-- 암호화된 비밀번호로 업데이트
UPDATE MEMBER SET
MEMBER_PW = 'aBN5hiegXlvAovJLipPoPd5LB+xjPrAeu1tcAVg0p5MKGocvo6l825SD+ZMCOcHBFeGB7MnzH31SAnDzYYsSdg=='
WHERE MEMBER_NO = 1;
commit;
-> MEMBER 테이블의 데이터를 살펴보면 MEMBER_PW의 값이 변경된 것을 볼 수 있다!