반응형
구현 순서
- [서버] RSA 공개키를 자바스크립트 로그인 폼에 출력
- [클라] 로그인 시 자바스크립트에서 폼 데이터를 인터셉트 후 암호화 전송
- [서버] RSA 개인키로 수신한 폼 데이터를 복호화
ி 로그인 페이지 접근 - 서버 공개키 / 개인키 생성
@RequestMapping(value = "/", method = RequestMethod.GET) public String Login(HttpSession session, HttpServletRequest request,HttpServletResponse response, Model model) throws Exception, NoSuchAlgorithmException { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048); // 키 사이즈 - 1024, 2048 KeyPair keyPair = generator.genKeyPair(); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // 개인 키 생성 후 세션에 저장 session.setAttribute("__rsaPrivateKey__", privateKey); // 공개키를 문자열로 변환 RSAPublicKeySpec publicSpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class); String publicKeyModulus = publicSpec.getModulus().toString(16); String publicKeyExponent = publicSpec.getPublicExponent().toString(16); // 로그인 폼 Input hidden 값 설정 request.setAttribute("publicKeyModulus", publicKeyModulus); request.setAttribute("publicKeyExponent", publicKeyExponent); return "Login"; }
ி 로그인 페이지 - 전송 데이터 암호화
RSA 암호화를 위한 js 라이브러리
<title>Login</title> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <!-- RSA 자바스크립트 라이브러리(순서 중요) --> <script type="text/javascript" src="/resources/js/RSA/jsbn.js"></script> <script type="text/javascript" src="/resources/js/RSA/rsa.js"></script> <script type="text/javascript" src="/resources/js/RSA/prng4.js"></script> <script type="text/javascript" src="/resources/js/RSA/rng.js"></script> $("#loginBtn").on("click", function(){ // 이용자 입력 값 저장 var uid = $("#userId").val(); var pwd = $("#userPass").val(); // 서버로부터 수신한 공개키로 RSA 암호화 생성 var rsa = new RSAKey(); rsa.setPublic($("#rsaPublicKeyModulus").val(),$("#rsaPublicKeyExponent").val()); // 이용자 입력 값 암호화 처리 uid = rsa.encrypt(uid); pwd = rsa.encrypt(pwd); // 암호화 값이 보이지 않게 hidden 로그인 폼으로 데이터 전달 $("#securedUsername").val(uid); $("#securedPassword").val(pwd); $("#securedLoginForm").submit(); // location.href="/member/login.do"; }) <!-- 서버에서 전달받은 공개키를 hidden에 설정한다. --> <input type="hidden" id="rsaPublicKeyModulus" value="${publicKeyModulus}" /> <input type="hidden" id="rsaPublicKeyExponent" value="${publicKeyExponent}" /> <h2>로그인</h2> <input type="text" id="userId" name="userId" style="margin-top:5px;"> </div> <div> <input type="password" id="userPass" name="userPass"> </div><br> <div> <button id="loginBtn" class="btn btn-success">로그인</button> </div> <form id="securedLoginForm" name="securedLoginForm" action="/member/login.do" method="post" style="display: none;"> <input type="hidden" name="securedUsername" id="securedUsername" value="" /> <input type="hidden" name="securedPassword" id="securedPassword" value="" /> </form>
ி 서버 개인키 - 데이터 복호화
public class MemberController { // 복호화 함수 정의 private String decryptRsa(PrivateKey privateKey, String securedValue) throws Exception { System.out.println("will decrypt : " + securedValue); Cipher cipher = Cipher.getInstance("RSA"); byte[] encryptedBytes = hexToByteArray(securedValue); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); String decryptedValue = new String(decryptedBytes, "utf-8"); // 문자 인코딩 return decryptedValue; } // 16진수 문자열을 바이트 배열로 변환 public static byte[] hexToByteArray(String hex) { if (hex == null || hex.length() % 2 != 0) { return new byte[]{}; } byte[] bytes = new byte[hex.length() / 2]; for (int i = 0; i < hex.length(); i += 2) { byte value = (byte)Integer.parseInt(hex.substring(i, i + 2), 16); bytes[(int) Math.floor(i / 2)] = value; } return bytes; } @RequestMapping(value = "/member/login.do", method = RequestMethod.POST) public String login(MemberVO vo,HttpServletRequest request,HttpServletResponse response, HttpSession session) throws Exception{ // 세션에 저장된 개인키를 불러온다. PrivateKey privateKey = (PrivateKey)session.getAttribute("__rsaPrivateKey__"); session.removeAttribute("__rsaPrivateKey__"); // 키 재사용 방지 if (privateKey == null) { throw new RuntimeException("암호화 비밀키 정보를 찾을 수 없습니다."); } try { // 개인키로 데이터를 복호화한다. String username = decryptRsa(privateKey, vo.getUserId()); String password = decryptRsa(privateKey, vo.getUserPass()); request.setAttribute("username", username); request.setAttribute("password", password); } catch (Exception ex) { throw new ServletException(ex.getMessage(), ex); } return "redirect:/"; // } }
반응형
'해킹-보안' 카테고리의 다른 글
톰캣 에러 페이지 처리 및 버전 정보 삭제 (0) | 2021.02.01 |
---|---|
톰캣 8.5 사설 SSL 인증서 설치 (0) | 2021.01.31 |
Mybatis $와 # 차이 (0) | 2021.01.13 |
오라클과 Mybatis 연동하기 (0) | 2021.01.12 |
DirBuster를 활용한 웹 서버 파일 및 디렉터리 스캔 (0) | 2021.01.11 |