로그인 시 비밀번호 javascript 암호화 -> java 복호화 -- JSP, SPRING



프로젝트 보안취약점 지적사항 중에 로그인화면에서 로그인 시도 시 비밀번호가 평문으로 전달되면 안된다는 것이 있었다.
아래의 문서를 찾아 적용하였고 정리해둔다.


javascript - java 간 RSA 를 이용해서 암호화 복호화 하기

1) javascript encrypt library 다운로드

- jsbn.js, prng4.js, rng.js, rsa.js


2) JSP

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String ctxPath = (String) request.getContextPath();
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Login</title>
<script type="text/javascript" src="<%=ctxPath %>/script/jquery/jquery-1.11.0.min.js"></script>
<!-- 순서에 유의 -->
<script type="text/javascript" src="<%=ctxPath %>/script/RSA/rsa.js"></script>
<script type="text/javascript" src="<%=ctxPath %>/script/RSA/jsbn.js"></script>
<script type="text/javascript" src="<%=ctxPath %>/script/RSA/prng4.js"></script>
<script type="text/javascript" src="<%=ctxPath %>/script/RSA/rng.js"></script>
 
<script type="text/javascript">    
    function login(){
        var id = $("#USER_ID_TEXT");
        var pw = $("#USER_PW_TEXT");
    
        if(id.val() == ""){
            alert("아이디를 입력 해주세요.");
            id.focus();
            return false;
        }
        
        if(pw.val() == ""){
            alert("비밀번호를 입력 해주세요.");
            pw.focus();
            return false;
        }
        
        // rsa 암호화
var rsa = new RSAKey();
rsa.setPublic($('#RSAModulus').val(),$('#RSAExponent').val());
        
$("#USER_ID").val(rsa.encrypt(id.val()));
$("#USER_PW").val(rsa.encrypt(pw.val()));
        
        id.val("");
        pw.val("");
 
        return true;
    }
</script>
</head>
<body>
    <form name="frm" method="post" action="<%=ctxPath%>/login.do" onsubmit="return login()">
<input type="hidden" id="RSAModulus" value="${RSAModulus}"/>
<input type="hidden" id="RSAExponent" value="${RSAExponent}"/>    
        <input type="text" placeholder="아이디" id="USER_ID_TEXT" name="USER_ID_TEXT" />
        <input type="password" placeholder="비밀번호" id="USER_PW_TEXT" name="USER_PW_TEXT" />
        <input type="hidden" id="USER_ID" name="USER_ID">
        <input type="hidden" id="USER_PW" name="USER_PW">
        <input type="submit" value="로그인" />
    </form>
</body>
</html>


3) JAVA

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
 
import javax.crypto.Cipher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
@Controller("loginController")
public class LoginController {
 
    private static String RSA_WEB_KEY = "_RSA_WEB_Key_"; // 개인키 session key
    private static String RSA_INSTANCE = "RSA"; // rsa transformation
 
    // 로그인 폼 호출
    @RequestMapping("/loginForm.do")
    public ModelAndView loginForm(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
        // RSA 키 생성
initRsa(request);
 
        ModelAndView mav = new ModelAndView();
        mav.setViewName("loginForm");
        return mav;
    }
 
    // 로그인
    @RequestMapping("/login.do")
    public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception {
 
        String userId = (String) request.getParameter("USER_ID");
        String userPw = (String) request.getParameter("USER_PW");
 
        HttpSession session = request.getSession();
        PrivateKey privateKey = (PrivateKey) session.getAttribute(LoginController.RSA_WEB_KEY);
 
// 복호화
userId = decryptRsa(privateKey, userId);
userPw = decryptRsa(privateKey, userPw);
 
// 개인키 삭제
session.removeAttribute(LoginController.RSA_WEB_KEY);
 
        // 로그인 처리
        /*
          
         ...  
           
         */
 
        ModelAndView mav = new ModelAndView();
        mav.setViewName("index");
        return mav;
    }
 
    /**
     * 복호화
     * 
     * @param privateKey
     * @param securedValue
     * @return
     * @throws Exception
     */
    private String decryptRsa(PrivateKey privateKey, String securedValue) throws Exception {
        Cipher cipher = Cipher.getInstance(LoginController.RSA_INSTANCE);
        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진 문자열을 byte 배열로 변환한다.
     * 
     * @param hex
     * @return
     */
    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;
    }
 
    /**
     * rsa 공개키, 개인키 생성
     * 
     * @param request
     */
    public void initRsa(HttpServletRequest request) {
        HttpSession session = request.getSession();
 
        KeyPairGenerator generator;
        try {
            generator = KeyPairGenerator.getInstance(LoginController.RSA_INSTANCE);
            generator.initialize(1024);
 
            KeyPair keyPair = generator.genKeyPair();
            KeyFactory keyFactory = KeyFactory.getInstance(LoginController.RSA_INSTANCE);
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
 
            session.setAttribute(LoginController.RSA_WEB_KEY, privateKey); // session에 RSA 개인키를 세션에 저장
 
            RSAPublicKeySpec publicSpec = (RSAPublicKeySpec) keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
            String publicKeyModulus = publicSpec.getModulus().toString(16);
            String publicKeyExponent = publicSpec.getPublicExponent().toString(16);
 
            request.setAttribute("RSAModulus", publicKeyModulus); // rsa modulus 를 request 에 추가
            request.setAttribute("RSAExponent", publicKeyExponent); // rsa exponent 를 request 에 추가
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


핑백

덧글

댓글 입력 영역