본문 바로가기
기타Tip

HTML에서 javascript로 AES암호화하기

by 크라크라 2023. 12. 8.

서비스를 개발하다보면 html 에서도 암호화 로직을 구현할 필요가 생깁니다. 

완전히 서비스가 분리되어있고, react나 vue 등을 이용해서 프론트 페이지를 구축하는 경우에는 모듈을 받은 뒤에 암호화를 구축하면 되지만 특별한 라이브러리를 쓰지 않고, 순수 HTML + javascript 로 만들어진 페이지에서 구현할 때에 쉽게 하는 방법을 공유드립니다. 

 

일단 crypto-js 라는 라이브러리가 필요합니다. 

github 에서 직접 코드를 받아서 구축하는 방법도 가능하겠지만, cdn 을 사용합시다. 

 

https://cdnjs.com/libraries/crypto-js 에서 원하는 버전, 원하는 파일들을 모두 가져오면 됩니다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>

 

그리고 이 라이브러리를 이용한 암/복호화 함수를 간단하게 구현합니다. 

저는 thymeleaf 를 이용한 html을 사용하고 있기 때문에 `script th:inline` 이라는 내용이 추가되어있는데 각자 html 을 사용하는 방식에 맞춰서 사용하면 될 것 같습니다. 

 

 iv 와 key 값은 뷰에서 addobject로 넣어주었습니다만은, 실제로 운영에서 사용되는 페이지에서는 이렇게 쓰시면 중요한 키값이 노출되기 때문에 이렇게 사용하시면 안됩니다. 예시로 생각해주세요.

 

cipher 의 타입을 AES 로 정의하고, iv와 key 값은 모두 Utf8 로 받아오도록 정의해줍니다. 마찬가지로 암호화시에 사용하는 padding 로직과 mode 를 맞춰서 정의해주면 됩니다. 현재 버전에서는 실제로 Java에서 암호화할 때 아래와 같은 방식으로 암/복호화 로직이 되어있는 것이라고 볼 수 있습니다.

Cipher c = Cipher.getInstance("AES/CBC/PKCS7Padding");

 

옛날에 구현된 많은 로직들이 AES/CBC/PKCS5Padding 으로 되어있을텐데 최신 Crypto-js 라이브러리에서는 PKCS7Padding 만을 지원합니다. 다만, 공식적으로 사용하는 블록이 PKCS5 는 8바이트 크기로 고정되어있고 PKCS7 의 경우에는 1~255바이트로 가변이라는 점이 다르다고 합니다. 그렇지만 기본적인 암호화 설정을 그대로 사용하고 있었다면 그대로 호환이 된다고 하네요. 

<script th:inline="javascript">
	const encrypt = (target) => {
        let key = "[(${aes_key})]";
        let iv = "[(${aes_iv})]";
        let cipher = CryptoJS.AES.encrypt(target, CryptoJS.enc.Utf8.parse(key),{
          iv : CryptoJS.enc.Utf8.parse(iv),
          padding : CryptoJS.pad.Pkcs7,
          mode: CryptoJS.mode.CBC
        });

        let encTarget = cipher.toString()
        return encTarget;
      }

      const decrypt = (target) => {
        let key = "[(${aes_key})]";
        let iv = "[(${aes_iv})]";
        const cipher = CryptoJS.AES.decrypt(target, CryptoJS.enc.Utf8.parse(key),{
          iv : CryptoJS.enc.Utf8.parse(iv),
          padding : CryptoJS.pad.Pkcs7,
          mode: CryptoJS.mode.CBC
        });

        let decTarget = cipher.toString(CryptoJS.enc.Utf8)
        return decTarget;
      }
</script>

 

 혹시나 사내에서 사용할 API 테스트 페이지를 만드는데 암호화 로직을 분리해서 만드느라 고통 받으셨던 분들은 이 방식을 이용해보시면 어떨까합니다.

댓글