4,563,035 th visitor since 2017.2.1 ( Today : 486 )
Programming
No. 402
Name. swindler
Subject. Secure Communications with JSSE
Main Cate. Java
Sub Cate.
Date. 2007-11-07 15:20
Hit. 19596 (211.36.27.8)
File.
JSSE 이용한 안전한 커뮤니케이션
Java Secure Socket Extension (JSSE) 라이브러리는 J2SE 1.4 플랫폼의 기본적인 부분이다. 이전 버전에서는 썬의 레퍼런스 임플리멘테이션이나 다른 회사로부터 standard extension 라이브러리의 설치가 필요했었다. 라이브러리는 안전한 HTTP 요청과 응답의 핸들링을 지원하며, HTTPS 또는 SSL을 이용한 HTTP로도 알려져 있다. 보다 자세하게 설명하자면, JSSE 라이브러리는 인증(authentication), 암호화(encryption), 통합성(integrity)에 필요한 기능을 제공한다. 이러한 지원을 통해 네트워크로 전송된 데이터는 비공개이며 clear text (공개적으로 볼 수 있고 이해 가능한 텍스트)가 아니라는 것을 보장한다.

javax.net.ssl 패키지는 Secure Sockets Layer (SSL)과 Transport Layer Security (TLS) 프로토콜을 통한 커뮤니케이션을 위한 API를 포함하고 있다. SSL과 TLS는 안전한 네트워크 트래픽을 위해 밀접하게 연관되어있는 두 프로토콜이다. 인증은 X.509 인증서를 사용함으로써 제공되는데, 이 인증은 단지 서버 뿐 아니라 클라이언트에서도 사용 가능하다. 게다가 JSSE 라이브러리는 비밀 키 교환과 공개 키 인증서를 통한 암호화를 제공한다. 암호화는 메시지의 통합성을 보장하면서, 커뮤니케이션 도중 메시지를 가로채서(intercept) 변경하고, 마치 바뀌지 않은 것처럼 다시 전달하는 것을 방지한다.

만약 다이렉트 소켓의 사용과 HTTP 커맨드 자체의 전송에 관심이 없다면 지난 2004년 2월 10일자 테크팁인 Using HttpURLConnection to Access Web Pages에서 보여준 HttpsURLConnection 클래스를 사용할 수도 있다. HttpsURLConnection 클래스는 리디렉션(redirection), 접속 재시도, 프록시 교섭(negotiation), J2SE 버전5의 쿠키들과 같은 기능들을 모두 지원한다.

HTTP/HTTPS 트랜잭션이나 사용자 애플리케이션 레벨에서의 사용을 위해 소켓을 직접적으로 활용하고 싶다면 javax.net.ssl 패키지와 javax.net의 팩토리들을 결합할 수 있다. 이는 HTTPS를 실행해서 보안화된 접속을 통해 커뮤니케이션할 수 있도록 허용한다. HTTP Socket 접속을 통한 커뮤니케이션에 익숙하다면, SSL 기반의 소켓을 사용하는 일도 그와 별다를 바 없다는 것을 알게 될 것이다. 일반적인 웹 트래픽을 위한 80포트 대신에 443 포트를 사용한다는 점이 다를 뿐이다.

안전하게 커뮤니케이션 하기 위해서, 우선 소켓 팩토리가 필요하다. 팩토리로부터 특정 호스트와 포트를 위한 소켓을 생성한다. 소켓을 위해 Socket 컨스트럭터를 호출하는 대신 SocketFactory를 요청한다. SocketFactory는 javax.net.ssl.SSLSocketFactory 팩토리의 디폴트 SSL 버전이다.

SocketFactory factory = SSLSocketFactory.getDefault();
Socket socket =
factory.createSocket(hostname, HTTPS_PORT);

그 이후의 프로세스는 HTTP 기반의 소켓을 사용하는 것과 본질적으로 동일하다. 서버에 요청을 보내고, 응답을 받게 된다.

// Send Request
OutputStream outputStream =
socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream);
out.print("GET / HTTP/1.0\r\n\r\n");
out.flush();

// Get Response
InputStream inputStream =
socket.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream);
BufferedReader in =
new BufferedReader(inputStreamReader);

String line;

while ((line = in.readLine()) != null) {
System.out.println(line);
}

다음은 앞서 살펴 본 내용을 이용해서 만든 SSLClient 프로그램이다.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {
private static final int HTTPS_PORT = 443;

public static void main(String args[]) {

if (args.length == 0) {
System.err.println
("Please provide a hostname to connect to");
System.exit(-1);
}

String hostname = args[0];

try {

// Get the default SSL socket factory
SocketFactory factory =
SSLSocketFactory.getDefault();

// Using socket factory, get SSL socket to port on host
Socket socket =
factory.createSocket(hostname, HTTPS_PORT);

// Send request to get root
// Be sure to end string with two sets of carriage
// return - newline characters.
OutputStream outputStream =
socket.getOutputStream();
PrintWriter out = new PrintWriter(outputStream);
out.print("GET / HTTP/1.0\r\n\r\n");
out.flush();

// Fetch response
InputStream inputStream =
socket.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream);
BufferedReader in =
new BufferedReader(inputStreamReader);

String line;

while ((line = in.readLine()) != null) {
System.out.println(line);
}

// Close everything
out.close();
in.close();
socket.close();

} catch (IOException e) {
System.err.println("Problems talking to " + hostname);
e.printStackTrace();
}
}
}

프로그램을 실행하면, 커뮤니케이션 하고자 하는 호스트의 이름을 넘겨주게 된다. Tomcat을 로컬에서 실행하는 것을 고려하거나 sun.com에 접속하자. SSLClient의 포트 상수는 443임을 주의하자. 필요하다면 프로그램에서 HTTPS 포트 상수를 변경하거나, 프로그램을 변경해서 커맨드 라인에 상수를 지정해줄 수도 있다.

HTTPS 포트를 통한 커뮤니케이션의 결과는 일반 HTTP 포트를 통해 커뮤니케이션 하여 얻은 결과와 다를 지도 모른다. 출력결과를 저장하여 브라우저에서 살펴보아라. 날짜, 시간, 서버와 같은 표준 헤더 값을 없애야만 한다. 만일 사이트가 어느 서버를 사용하는지 궁금하다면 서버 주소는 물론 남겨둬야만 한다. 예를 들어 SSLClient 프로그램을 통해 www.sun.com에 접속해보면

java SSLClient www.sun.com

다양한 헤더 필드 안에서 SunONE WebServer 6.0를 사용하고 있음을 보여준다.

HTTP/1.1 200 OK
Server: SunONE WebServer 6.0
Date: Tue, 03 Aug 2004 22:30:32 GMT
P3p: policyref="http://www.sun.com/p3p/Sun_P3P_Policy.xml",
...

클라이언트는 원하는 호스트와 커뮤니케이션하고 있다는 것을 확인하기 위해 받은 자격 증명서(credentials)를 검토해야만 한다. socket.getSession()이나 getPeerCertificates(), getPeerCertificates()를 사용하자. 누군가 악의적인 호스트로 접속을 재라우팅하는 것은 사소한 일이 아니며, 증명서를 검토하는 것은 이를 체크하는 한가지 방법인 것이다. 호스트 이름을 조회하기 위해 HostnameVerifier 인터페이스를 사용할 수도 있다.

보안을 중시하는 개발자들과 유저들은 J2SE 1.4.2 download 페이지에서 사용제한 없는 Java Cryptography Extension (JCE) 정책 파일을 다운로드 받길 바란다. J2SE 1.4에 포함된 JCE 버전은 강력하지만 사용 제한이 있다. 만일 해당사항이 있는 국가에 거주한다면, 추가된 키사이즈 서포트를 사용하여 JSSE를 단독으로 사용하는 것보다 강력한 레벨의 암호기법 성능을 제공받을 수 있다.

JCE에 관해 더 알고 싶다면, JCE Reference Guide

JSSE에 관해 더 알고 싶다면, JSSE Reference Guide를 참조하기 바란다.



[바로가기 링크] : http://coolx.net/cboard/develop/402



Name
Password
Comment
Copyright © 1999-2017, swindler. All rights reserved. 367,611 visitor ( 1999.1.8-2004.5.26 ), 2,405,771 ( -2017.01.31)

  2HLAB   2HLAB_Blog   RedToolBox   Omil   Omil_Blog