본문 바로가기
etc/Netty

Netty Server에 SSL(https) 연결 적용하기

by 돈코츠라멘 2019. 10. 3.

SSL?

Netty에 SSL 인증을 적용하기 전 SSL 인증이 무엇인지, TLS Handshake는 어떤 프로세스로 동작하는지 설명한다. 대부분의 내용은 <자바 네트워크 소녀 Netty>를 참고하였다.

대칭키/공개키 암호화

대칭키 공개키(비대칭키)

암호화에 사용되는 키와 복호화에

사용되는 키가 동일

암호화에 사용되는 키와 복호화에

사용되는 키가 서로 다름

빠른 암복호화 성능, 구현이 비교적 간단 대칭키 암호화에 비해 상대적으로 낮은 성능

키가 유출되면 키를 공유한 상대방의 데이터를

모두 복호화 할 수 있음

키가 유출되어도 상대방의 데이터는 안전
  대표적으로 RSA가 여기에 속함

공개키 암호화에 대한 더욱 자세한 설명

공개키 암호화는 암복호화에 사용되는 키가 다르다. 즉, 한 명의 사용자가 가지는 키는 두 개가 된다. 예를들어 모모라는 사용자가 공개키 암호화를 사용하려 할 때 비밀키와 공개키 쌍을 만든다. 비밀키는 자신만 알고 있고, 공개키는 다른 사람들이 사용할 수 있게 한다. 누군가가 모모에게 메시지를 전송하고 싶다면 모모의 공개키를 사용하여 메시지를 암호화하고 그 메시지를 모모에게 전송하면 모모는 자신의 비밀키로 암호화된 메시지를 복호화하여 확인할 수 있다.

모모와 두두가 메시지를 주고 받고 싶을 때, 모모는 메시지 전송자가 두두라는 걸 어떤 방식으로 보장받을 수 있을까?

공개키 암호화에서 비밀키 공개키 쌍으로만 암복호화가 이루어지는 특징을 사용한다. 두두가 메시지를 전송할 때 먼저 모모의 공개키로 메시지를 암호화한 다음 자신의 비밀키로 다시 한 번 암호화하면 된다. 메시지를 수신한 모모는 먼저 두두의 공개키로 메시지를 복호화하고 자신의 비밀키로 다시 한 번 복호화하여 메시지를 두두가 전송한 것임을 보장받을 수 있다. 만약 두두가 보낸 메시지가 아니라면 복호화에 실패하게 되므로 두두가 전송한 메시지가 아님을 확인할 수 있다.

SSL/TLS

TLS는 SSL(Secure Sockets Layer)를 기반으로 한 보안 소켓 규격으로 네트워크로 전송되는 데이터를 암호화하여 보호하는 기술이다. TLS가 표준 명칭이지만 SSL이라는 용어가 대중적으로 사용되고 있다.

TLS Handshake Protocol

TLS Protocol은 앞에서 설명한 대칭키 암호화와 공개키 암호화를 동시에 사용하여 강력한 보안과 성능을 보장받으면서 네트워크 데이터를 보호한다. 먼저 클라이언트와 서버는 공개키 암호화 알고리즘을 통해 비밀키를 서로 공유하고 공유된 비밀키를 통해서 대칭키 암호화 알고리즘으로 데이터를 암호화하여 통신한다. 이것을 TLS Handshake Protocol이라고 한다.

 

 


 

Netty Server에 SSL 연결 적용

Netty의 채널 보안을 위해서 필요한 정보는 인증서, 개인키, 개인키의 암호다. Netty에 SSL/TLS 연결을 적용하는 방법은 매우 간단하다. 부트 스트랩을 생성할 때 앞에서 생성한 인증서와 개인키로 Netty의 SslContext 인스턴스를 생성하고 채널 파이프라인의 가장 앞쪽에 SslContext로부터 생성한 SslHandler를 등록하면 된다.

인증서 발급

Netty Server에 TLS Protocol을 적용하려면 공캐기 암호화에서 사용되는 인증서가 필요하다. 이 인증서는 웹 서버에서 사용하는 인증서와 동일하며 파일은 Pem 형식이어야 한다. 인증서는 JDK의 keytool과 같은 인증서 관리 도구나 OpenSSL 프로그램을 사용하여 만든다.

개인키 생성

$ openssl genrsa -aes256 -out privatekey.pem

키 생성도중에 unable to write 'random state' 에러가 발생하면 아래 포스트를 참고한다.

2019/08/30 - [Dev] - openssl에서 unable to write 'random state' 에러 발생원인 및 해결법

CSR 파일 생성

인증서 서명 요청을 위한 CSR 파일을 생성할 때 자동으로 공개키가 생성되어 포함된다. CSR 파일에는 파일을 생성한 기관의 공개키와 웹 서비스를 제공하는 회사의 정보를 암호화한 정보가 담겨있다.

$ openssl req -new -key privatekey.pem -out netty.csr

인증서 만들기

$ openssl x509 \
-in netty.csr -out netty.crt \
-req -signkey privatekey.pem \
-days 356

개인키 포맷 변경

Netty의 SslContext는 PKCS8 key만 사용할 수 있으므로 생성해둔 개인키의 포맷을 바꿔야 한다. (Netty 공식문서 참고)

The SslContextBuilder and so Netty´s SslContext implementations only support PKCS8 keys.
If you have a key with another format you need to convert it to PKCS8 first to be able to use it. This can be done easily by using openssl.

$ openssl pkcs8 -topk8 -nocrypt -in pkcs1_key_file -out pkcs8_key.pem
$ cp privatekey.pem privatekey.pem.org
$ openssl pkcs8 -topk8 -nocrypt \
-inform PEM -outform PEM \
-in privatekey.pem.org -out privatekey.pem

Netty Server

인증서와 개인키를 가지고 SslContext를 만들어서 반환하는 메서드를 만들었다. 이 결과를 채널 파이프라인을 만드는 부분에서 사용하면 된다.

private SslContext getCertificate() throws SSLException {
    if (getCertPath() != null && getKeyPath() != null) {
        File cert = new File(getCertPath()); // 인증서 파일
        File key = new File(getKeyPath()); // 개인키 파일
        return SslContextBuilder.forServer(cert, key).build();
    } else {
        logger.error("Certification or Key path is null");
        return null;
    }
}

참고로 <자바 네트워크 소녀 Netty>의 예제에서는 SslContextBuilder.forServer(cert, key).build()로 작성된 부분이 SslContext.newServerContext(cert, key)로 되어 있다. 하지만 newServerContext는 이미 deprecated! 그래서 SslContext 생성은
SslContextBuilder.forServer를 사용해야 한다.

Channel Pipeline

앞에서 만든 SslContext를 사용해서 채널 파이프라인 생성의 가장 앞쪽에 SslHandler를 등록한다.

protected void initChannel(SocketChannel channel) throws Exception {
    ChannelPipeline pipeline = channel.pipeline();

    if (sslCtx != null) {
        pipeline.addLast(sslCtx.newHandler(channel.alloc()));
    }
    pipeline.addLast(new HttpRequestDecoder());
    pipeline.addLast(new HttpObjectAggregator(65536));
    pipeline.addLast(new HttpResponseEncoder());
    // ...

}

 

 

 


Reference

  • 자바 네트워크 소녀 Netty

'etc > Netty' 카테고리의 다른 글

Netty의 주요 특징 - 비동기, 이벤트 기반  (0) 2019.08.30

댓글