Coding Planet

[Servlet] 암호화 필터 예제 본문

Server

[Servlet] 암호화 필터 예제

jhj.sharon 2023. 3. 27. 20:52
반응형

 

 

1. 암호화 필터(EncryptFilter)

(필터에 대한 설명은 이전 포스트 참고: https://sharonprogress.tistory.com/150)

 

  • 로그인을 기능을 구현하기 위해서는 이메일, 비밀번호가 일치하는 회원을 조회하는 과정이 필요하다. 이때 개인정보에 해당하는 비밀번호의 경우 개인정보보호법에 의해 암호화를 해야하는데, 이를 위해 암호화 필터가 필요하다.
  • 암호화 필터는 보안이 필요한 로그인, 회원가입, 비밀번호 변경, 회원 탈퇴등에 쓰이는 필터로 인코딩 필터와는 달리 선택적으로 사용되므로 url을 String[]로 설정해야한다.
  • 다만, 이 필터에서는 비밀번호 값을 재 세팅하는 것이 불가능해 Wrapper Class를 사용해 오버라이딩을 하고 그 값을 반환 받아야 한다.
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.EncrpytWrapper;

//암호화를 적용해야하는 요청: 로그인, 회원가입, 비밀번호 변경, 회원 탈퇴
// urlPatterns에 적용될 url이 여러개인 경우: String 배열 초기화 형태인 {}로 작성

@WebFilter(filterName="encrpytFilter", 
urlPatterns={"/member/login",
			 "/member/signUp",
			 "/member/myPage/changePw",
			 "/member/myPage/secession"})

public class EncrpytFilter 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에 비밀번호 담겨 있음
		//부모타입에 맞추기 위해 다운캐스팅 필요
		HttpServletRequest req =(HttpServletRequest)request;
		
		//파라미터를 다시 세팅하는 방법은 필터에서는 불가능!
		//Servlet의 Wrapper 클래스를 이용해소 HttpServletRequest의 메서드를 오버라이딩
		//-> 오버라이딩을 통해 비밀번호 암호화 진행

		
		EncrpytWrapper wrapper = new EncrpytWrapper(req);
	
		chain.doFilter(wrapper, response);
	}


}

 

 

2. EncryptWrapper 클래스

  • EncrpytWrapper를 호출한 filter로부터 HttpServletRequest 객체를 매개변수로 전달받는다.
  • 비밀번호를 암호화 하여 다시 세팅하기 위해 getParameter()를 오버라이딩 한다. 이때 getParameter()의 매개변수 String name은 사용자로부터 입력받안 태그의 name값이다.
  • 매개변수로 전달받은 값을 암호와 메서드로 세팅해 암호화된 값을 반환한다(value)
  • SHA-512 해시 함수는 어떤 문자열이든 일정한 길이의 무작위 문자열로 반환하는 암호화 함수이다.
  • 해당 메서드 내에서 단방향 해시 함수 값을 구할 때 사용하는 MessageDigest 클래스를 통해 암호화를 한다.
  • 이 때 MessageDigest는 호출, 리턴을 byte[]로 받기 때문에 String으로 변환하는 과정이 필요하다.
  • base64는 임의의 바이트 스트림을 화면에 표시할 수 있는 ASCII 문자들로 바꾸는 인코딩 방식을 의미한다.
  • 결국 SHA-512 해시 함수가 반환한 바이트 형식을 문자열로 전환하는 것이다.

(MessgaeDigest 클래스는 이 포스트를 참고! : https://sharonprogress.tistory.com/151)

 

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 EncrpytWrapper extends HttpServletRequestWrapper {
	//HttpServletRequestWrapper
	// - 클라이언트 요청 객체 HttpServletRequest를 오버라이딩 하는 방법을 제공하는 클래스
	
	//생성자가 작성되어 있으면
	//컴파일러가 기본 생성자 자동으로 추가 안해줌
	
	//->Wrapper 클래스 생성 시 반드시 HttpServletRequest 객체를 매개변수로 전달해야 한다.
	public EncrpytWrapper(HttpServletRequest request) {
		super(request);
		
	}

	//getParameter() 오버라이딩
	@Override
	public String getParameter(String name) {
		//매개변수 name : input 태그의 name 속성 값
		//return super.getParameter(name): 기존 getParameter()메서드
		
		String value = null;
		
		switch(name) {
		case "inputPw":
		case "memberPw" :
		case "currentPw" :
		case "newPw":
			value = getSha512(super.getParameter(name));
			
			break;
			
			//dafault: 암호화가 필요 없는 경우에는 기존 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) {
			e.printStackTrace();
			
		}
		
		return encryptPw;
	}
	
	
	
	
	
	

} //end of class
반응형
Comments