비밀번호 전송 양방향 암호화(rsa) 적용

  • view에서 서버로 계속 같은 비밀번호 전송하는걸 막기위해 rsa 양방향 암호화 적용

1.Rsa util 추가

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.HttpSession;

public class Rsa {

    public static String RSA_WEB_KEY = "_RSA_WEB_Key_"; // 개인키 session key
    public static String RSA_INSTANCE = "RSA"; // rsa transformation

    /**
     * 복호화
     *
     * @param privateKey
     * @param securedValue
     * @return
     * @throws Exception
     */
    public String decryptRsa(PrivateKey privateKey, String securedValue) throws Exception {
        Cipher cipher = Cipher.getInstance(Rsa.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(Rsa.RSA_INSTANCE);
            generator.initialize(1024);

            KeyPair keyPair = generator.genKeyPair();
            KeyFactory keyFactory = KeyFactory.getInstance(Rsa.RSA_INSTANCE);
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();

            session.setAttribute(Rsa.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();
        }
    }
}

2. jsp에 필요 js 추가 및 hidden 값추가

<script type="text/javascript" src="${_.contextPath}/resources/lib/RSA/rsa.js"></script>
<script type="text/javascript" src="${_.contextPath}/resources/lib/RSA/jsbn.js"></script>
<script type="text/javascript" src="${_.contextPath}/resources/lib/RSA/prng4.js"></script>
<script type="text/javascript" src="${_.contextPath}/resources/lib/RSA/rng.js"></script>
<form> ...
                                <input type="hidden" id="RSAModulus" value="${RSAModulus}"/>
                                <input type="hidden" id="RSAExponent" value="${RSAExponent}"/>
</form>

3. js에 암호화 로직 추가 및 암호화

// 비밀번호 암호화
function rsa(pwd){
    var pw = pwd;
    // rsa 암호화
    var rsa = new RSAKey();
    rsa.setPublic($('#RSAModulus').val(),$('#RSAExponent').val());
    return rsa.encrypt(pw);
}
function bindLoginSubmit() {
  $("#form_login").submit(function (e) {
    e.preventDefault();
    var form = this;
    var options = {
      method: form.method
      /*, data: $(form).serialize()*/
      , data: {
          "username" :  rsa($("input[name='username']").val())
          ,"password" : rsa($("input[name='password']").val())
      }
    };
})
};

4. WebSecurityConfig에 RequestContextListener 추가 (HttpRequest 불러오기위해)

    @Bean
    public RequestContextListener requestContextListener(){
        return new RequestContextListener();
    }

5. 복호화 및 암호화 AuthenticationProvider에 추가

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            ServletRequestAttributes servletRequestAttribute = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            HttpServletRequest request = servletRequestAttribute.getRequest();
            Rsa r = new Rsa();
            HttpSession session = request.getSession();
            //로그인전에 세션에 저장된 개인키를 가져온다.
            PrivateKey privateKey = (PrivateKey) session.getAttribute(Rsa.RSA_WEB_KEY);
            //암호화 된 비밀번호를 복호화 시킨다.
            String username = r.decryptRsa(privateKey, (String) authentication.getPrincipal());
            String password = r.decryptRsa(privateKey, (String) authentication.getCredentials());
            // ShA 256 암호화 = 단방향
            password = passwordEncoder.encode(password).replaceAll("\\{sha256}","");
        }
}

vue

  • 단일 페이지 어플리케이션

vue 설치

  1. 노드,NPM 설치
    • mac brew 사용시 명령어 brew install node
  2. vue cli 설치
    • 명령어 npm install -g @vue/cli
    • vue cli 는 vue project를 빠르게 구성하고, 빌드, 디플로이 할 수 있게 하는 도구.
  3. vue 프로젝트 생성 (vue-project)
    • 명령어 vue create vue-project
    • 여러설정이가능한 vue-project-manually 도 있다. 명령어 vue-project-manually
  4. 생성된 프로젝트로 접속해 vue 구동 테스트
    • 명령어 npm run serve -- --port 3000

vue 프로젝트 구조

node_modules : npm으로 설치된 패키지 파일들(자바로 치면 lib)
public : 웹팩을 통해 관리되지 않는 정적 리소스가 모여있는 디렉토리
src/asset : 이미지, css, 폰트 등을 관리하는 데렉토리
src/components : vue 컴포넌트 파일이 모여 있는 디렉토리
App.vue : 최상위(Root) zjavhsjsxm
main.js : 가장 먼저 실행되는 자바스크리브 파일로써, Vue 인스턴스를 생성하는 역할
babel.config.js : 바벨 설정 파일
package-lock.json : 설치된 package의 dependency 정보를 관리하는 파일
package.json : 프로젝트에 필요한 package를 정의하고 관리하는 파일

 

쿠키

 

HTTP는 무상태 프로토콜이기에 쿠키 미사용시엔 클라이언트가 서버에 접속했는지 계속 확인할 수 없다.

사용하는 예

1)로그인후에 유저 정보를 서버가 알기 위해 사용한다.

 

Set-Cookie

- 서버에서 클라이언트로 쿠키 전달(Response)

 

Cookie

- 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청 시 서버로 전달

 

즉, 서버가 쿠키를 전달하면 클라이언트는 저장하고 항상 보내준다.

모든 요청에 자동으로 포함한다.

 

보안을 위해 쿠키를 서버를 세팅할때 세션 아이디를 생성해서 사용한다.

세션 아이디를 통해 서버에서 누군지 해석한다.

 

사용처

- 사용자 로그인 세션 관리에서 사용한다.

- 광고 정보 트래킹

 

쿠키 정보는 항상 서버에 전동 됨

- 최소한의 정보만 사용

- 서버에 전송하지 않고, 웹 브라우저 내부에 데이터를 저장하고 싶으면 웹 스토리지(localStorage, sessionStorage) 참고

 

주의점

- 보안에 민감한 데이터는 저장하면 안 됨(주민번호, 신용카드 번호)


쿠키 생명주기

Expires(날짜), max-age(시간)

쿠키를 계속 유지할 수 없기에 날짜, 시간을 제한한다.

 

세션 쿠키

- 만료 날짜를 생략하면 브라우저 종료 시까지만 유지

 

영속 쿠키

- 만료 날짜를 입력하면 해당 날짜까지 유지


쿠키-도메인

명시

- 명시한 문서 기준 도메인+ 서브 도메인 포함

- domain=example.org로 설정할 경우

- example.orgdev.example.org 모두에 접근 가능하다.

 

생략 : 현재 문서 기준 도메인만 적용


쿠키 - 경로

이 경로를 포함한 하위 경로 페이지만 쿠키 접근

일반적으로 path=/ 루트로 지정


쿠키 - 보안

Secure, HttpOnly, SameSite

 

Secure

- Https에서만 전송한다.

 

HttpOnly

- XSS 공격 방비

- 자바스크립트에서 접근 불가(document.cookie)

- http 전송에만 사용

 

SameSite

- XSRF 공격 방지

- 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 전송

 

 

 

 

+ Recent posts