프로그래밍

[최종 프로젝트] SHA-256 암호화 본문

프로젝트

[최종 프로젝트] SHA-256 암호화

시케 2023. 9. 5. 01:08
728x90
반응형

SHA-256 암호화 알고리즘

프로젝트 구현 기능: 회원 관련 기능(로그인/회원가입/비밀번호 찾기)

직접 구현한 부분: 비밀번호 SHA-256 형식으로 암호화

기능 설명

회원의 정보 중 하나인 비밀번호 데이터를 SHA-256 형식으로 암호화하여 DB에 저장

SHA-256 암화화는 일방향 암호화 알고리즘으로 복호화가 불가능하므로 더욱더 강력한 보안을 가능케 함

 

여기서 SHA-256 알고리즘이란?

SHA는 Secure Hash Algorithm의 약어로 해쉬함수를 사용하는 암호화 알고리즘이다

256비트로 구성되어있고 64자리의 문자열을 반환한다

우리는 자바에서 제공하는 security 패키지를 통해 이를 구현할 것이다

 

코드 구현

회원가입시 회원이 입력한 비밀번호를 전달받아 솔트 값과 합쳐 문자열을 만든다

이때 솔트 값은 10자리의 랜덤 문자열이다

 

사용자입력 비밀번호+솔트 값을 SHA-256 알고리즘을 통하여 해시값으로 변경한다

이렇게 나온 해시값이 DB MEMBER_PW 칼럼에 저장되는 실제 데이터이다

64bit의 긴 해시 문자열이기 때문에 데이터베이스를 보는 관리자 또한 사용자가 입력하는 비밀번호를 알지 못하게 된다

 

여기서 솔트값을 사용하는 이유는 레인보우 테이블의 등장 때문이다

비밀번호를 평문에서 SHA-256 변환한 값으로 저장한다고 해도

보통의 사용자가 자주 쓰는 값은 원본-해시값 쌍으로 저장되어 있는 레인보우 테이블에 이미 존재할 확률이 높다

그렇기에 아예 랜덤 문자열인 솔트를 생성하여 평문 문자열에 덧붙여 암호화 하는것이다

 

기본 문자열이 길수록 해당 알고리즘과 보안을 파훼하기 어려워지기 때문에

특정 문자열을 랜덤 생성하여 덧붙여주는 것이다

 

로그인시에는 사용가 입력한 아이디의 값으로 솔트값을 가져와

다시 한번 암호화 하는 방식으로 진행된다

이렇게 복호화하는 것이 아닌 사용자가 입력한 값을 다시 암호화하여 비교하는 것이

바로 앞서 말한 일방향 암호 알고리즘이기 때문이다

 

SHA-256 알고리즘

// 비밀번호 sha256 형식으로 암호화
public static String ShaPass(String planText) {
	try {
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(planText.getBytes());
		byte byteData[] = md.digest();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < byteData.length; i++) {
			sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
		}
		StringBuffer hexString = new StringBuffer();
		for (int i = 0; i < byteData.length; i++) {
			String hex = Integer.toHexString(0xff & byteData[i]);
			if (hex.length() == 1) {
				hexString.append('0');
			}
			hexString.append(hex);
			}
		return hexString.toString();
	} catch (Exception e) {
		e.printStackTrace();
		throw new RuntimeException();
	}
}

 

로그인 예제 컨트롤러

@RequestMapping(value = "/login.do", method=RequestMethod.POST) // 로그인
	public String login(MemberVO memberVO, HttpSession session, Model model) {

		memberVO.setMemberSearch("솔트");
		String pw = memberVO.getMemberPw();
		String salt = memberService.selectOne(memberVO).getMemberSalt(); // 회원의 솔트값 가져옴
		String shaPW = Password.ShaPass(pw+salt);
		memberVO.setMemberPw(shaPW);

		memberVO.setMemberSearch("로그인");
		memberVO = memberService.selectOne(memberVO);
		
		if (memberVO != null) {
			session.setAttribute("sessionMemberId", memberVO.getMemberId());
			
		} else {
			AlertVO sweetAlertVO = new AlertVO("로그인실패", "로그인실패", null, "error", null);
			model.addAttribute("sweetAlert", sweetAlertVO);
			return "alertFalse.jsp";
		}
		return "redirect:main.do";
	}

 

문제해결

먼저 어려웠던 점은 왜 salt 를 사용해야 하는지 였는데

레인보우 테이블의 존재를 알고 공부하여 존재의 필요성을 깨닫게 되었고

구현 후에는 비밀번호 값이 암호화 되어 나타나기 때문에

로직 구현에 있어서 오류가 발생하였을때 어느 값과 해당 결과가 맞는지 직접 확인하는 것이 어려움이 있었다

 

개선점

비밀번호 찾기 기능에서 임시 비밀번호를 발급받는데

기존에 DB에서는 해시값으로 존재하는 비밀번호여서 해당 비밀번호가 임시값인지 아닌지

판단할 수 없었지만 솔트 값에 특정 특수문자등을 추가하여 구분하는 방식으로

임시 비밀번호 로그인시 비밀번호 변경을 안내할 수 있도록 할 수 있을 것 같다

 

728x90
반응형
Comments