AJAX 데이터 평문전송 암호화하기 (RSA 암호화)

RSA 암호화

RSA 암호는 공개기 암호시스템의 하나로 암호화뿐 아니라 전자서명이 가능한 최초의 알고리즘으로 알려져 있습니다.

RSA가 갖는 전자서명 기능은 인증을 요구하는 전자 상거래 등에 RSA의 광범위한 활용을 가능하게 하였습니다.


암호화 방식

RSA는 두개의 키 ( 공개키, 개인키 ) 를 사용합니다.

키란 메세지를 열고 잠그는 상수(constant)를 의미하며 일반적으로 많은 공개키 알고리즘의 공개키는 모두에게 알려져 있고 메세지를 암호화(encrypt) 하는데 쓰이며, 암호화된 메세지는 개인키(private key)를 가진 자만이 복호화(decrypt)하여 열어볼 수 있습니다.


RSA 암호화의 개요, 증명, 예시 등 자세한 내용은 RSA 암호 위키백과 에 자세히 나와 있습니다.

한번 살펴보시길 바래요!


사용하게된 이유

필요한 자원을 얻기 위해서 ajax를 사용하고 갱신을 위해 form submit을 통한 데이터 전송을 합니다.

https SSL 을 활용하여 데이터를 암호화해 전송하는 방법도 있지만 개발자도구, fiddler 에서 확인하면 데이터의 값이 그대로 노출되어 보안에 취약합니다.

로그인하는 과정에서 ID, PW 정보가 노출된다면 보안에 취약할 수 밖에 없습니다.


사용방법

1. 서버에서부터 암호화 할 공개키를 세션에 담아 클라이언트에 제공하고 공개키로 데이터를 암호화 후 서버로 전송합니다.

2. 클라이언트에서 받은 암호화된 데이터를 서버에서 개인키로 복호화합니다.


* 웹페이지를 호출할 때 마다 RSAModulus (키값) 이 변경되어 클라이언트에 전송되기 때문에 클라이언트에 전송되는 키값은 매번 변경됩니다.


사용예시 소스

1. Rsa.java 파일

  1. public class Rsa {
  2. public static final String RSA_WEB_KEY = "_RSA_WEBKEY_"; // 개인키 session key
  3. public static final String RSA_INSTANCE = "RSA"; // rsa transformation
  4.     /**
  5. * rsa 공개키, 개인키 생성
  6. * @param request
  7. */
  8. public static void initRsa(HttpServletRequest request) {
  9. HttpSession session = request.getSession();
  10. KeyPairGenerator generator;
  11. try {
  12. generator = KeyPairGenerator.getInstance(RSA_INSTANCE);
  13. generator.initialize(1024);
  14. KeyPair keyPair = generator.genKeyPair();
  15. KeyFactory keyFactory = KeyFactory.getInstance(RSA_INSTANCE);
  16. PublicKey publicKey = keyPair.getPublic();
  17. PrivateKey privateKey = keyPair.getPrivate();
  18. session.setAttribute(RSA_WEB_KEY, privateKey); // session에 RSA 개인키를 세션에 저장
  19. RSAPublicKeySpec publicSpec = (RSAPublicKeySpec) keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
  20. String publicKeyModulus = publicSpec.getModulus().toString(16);
  21. String publicKeyExponent = publicSpec.getPublicExponent().toString(16);
  22. request.setAttribute("RSAModulus", publicKeyModulus); // rsa modulus 를 request 에 추가
  23. request.setAttribute("RSAExponent", publicKeyExponent); // rsa exponent 를 request 에 추가
  24. } catch (Exception e) {
  25. // TODO Auto-generated catch block
  26. e.printStackTrace();
  27. }
  28. }
  29. /**
  30. * 복호화
  31. *
  32. * @param privateKey
  33. * @param securedValue
  34. * @return
  35. * @throws Exception
  36. */
  37. public static String decryptRsa(PrivateKey privateKey, String securedValue) throws Exception {
  38. Cipher cipher = Cipher.getInstance(RSA_INSTANCE);
  39. byte[] encryptedBytes = hexToByteArray(securedValue);
  40. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  41. byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
  42. String decryptedValue = new String(decryptedBytes, "utf-8"); // 문자 인코딩 주의.
  43. return decryptedValue;
  44. }
  45. /**
  46. * 16진 문자열을 byte 배열로 변환한다.
  47. *
  48. * @param hex
  49. * @return
  50. */
  51. public static byte[] hexToByteArray(String hex) {
  52. if (hex == null || hex.length() % 2 != 0) { return new byte[] {}; }
  53. byte[] bytes = new byte[hex.length() / 2];
  54. for (int i = 0; i < hex.length(); i += 2) {
  55. byte value = (byte) Integer.parseInt(hex.substring(i, i + 2), 16);
  56. bytes[(int) Math.floor(i / 2)] = value;
  57. }
  58. return bytes;
  59. }
  60. }


2. script ajax 호출

* RSAModules와 RSAExponent 변수는 hidden 값으로 사용했습니다.

  1. var form = $('[name=form]').serializeObject();
  2. var rsa = new RSAKey();
  3. rsa.setPublic($('#RSAModulus').val(), $('#RSAExponent').val());
  4. form.userId = rsa.encrypt(form.userId);
  5. form.userPwd = rsa.encrypt(form.userPwd);
  6. $.ajax({
  7. data: form,
  8. type: "POST",
  9. url: "/doLogin",
  10.     sendDataType : "json",
  11. dataType : 'json',
  12. success: function(res) {
  13. ...
  14. }
  15. });



* 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
작성자 소개
초이 프로필
WrapUp 블로거

초이

반려견을 좋아하고, 차를 좋아하고, 여행을 좋아하고, 맛집을 찾아 즐기는 웹 개발자 입니다^^