[JAVA] HTTPS통신시 인증서 검증 없이 통신처리하기

2022. 2. 9. 14:37자바

반응형

코드 제목: SSL 인증서 검증 우회 설정

이 코드는 HTTPS 연결을 할 때 SSL 인증서를 검증하지 않도록 설정하는 방법을 보여줍니다. 일반적으로 HTTPS 연결은 서버의 SSL 인증서를 확인하여 해당 서버가 신뢰할 수 있는지 판단합니다. 그러나 이 코드에서는 인증서 검증을 생략하고, 모든 서버 인증서를 신뢰하는 방식으로 설정하고 있습니다. 주로 테스트 환경이나 인증서를 신뢰할 수 없는 서버와의 통신에서 사용할 수 있습니다. 그러나 보안상의 이유로 실제 서비스에서 사용하지 않는 것이 좋습니다.

코드 흐름과 설명:

1. URL 객체 생성

url = new URL(addr);
  • 주어진 주소(addr)를 이용해 URL 객체를 생성합니다.
  • 이 객체는 우리가 연결하려는 웹사이트서버의 주소를 나타냅니다.
  • addr에는 예를 들어 "https://example.com" 같은 URL이 들어갑니다.

2. TrustManager 설정: 모든 인증서 신뢰

TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        // 인증서 검증을 생략
    }
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        // 인증서 검증을 생략
    }
}};
  • TrustManager는 서버의 SSL 인증서를 검증하는 역할을 합니다. 정상적인 경우, 서버가 제공하는 인증서를 확인하여 신뢰할 수 있는 인증기관(CA)에서 발급된 인증서인지를 판단합니다.
  • 여기서 X509TrustManager를 구현한 익명 클래스를 사용하여 모든 인증서를 신뢰하도록 설정합니다.
  • 중요한 부분:
    • checkServerTrusted와 checkClientTrusted는 빈 메서드로 구현되어 있습니다. 즉, 인증서 검증을 아예 하지 않게 만들고 있습니다.
    • getAcceptedIssuers()는 신뢰할 수 있는 인증 기관들을 반환하는데, null을 반환하므로 모든 인증서를 신뢰하게 됩니다.

3. SSLContext 설정 및 초기화

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
  • SSLContext는 SSL 연결을 설정하는 객체입니다. getInstance("SSL")을 통해 SSL 프로토콜을 사용할 수 있게 됩니다.
  • sc.init(...)에서는 SSLContext를 실제로 초기화합니다.
    • null: KeyManager는 사용하지 않으므로 null을 넣습니다.
    • trustAllCerts: 앞에서 설정한 모든 인증서를 신뢰하는 TrustManager 배열을 넣습니다.
    • SecureRandom(): 보안을 위한 랜덤값을 생성하는 객체입니다. 주로 암호화에서 사용됩니다.

4. HTTPS 연결을 위한 기본 SSL 소켓 팩토리 설정

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
  • sc.getSocketFactory()는 SSLContext에서 생성된 소켓 팩토리를 반환합니다.
  • HttpsURLConnection.setDefaultSSLSocketFactory(...)는 이 소켓 팩토리를 전체 HTTPS 연결에 기본값으로 설정합니다. 즉, 이후에 생성되는 모든 HTTPS 연결은 이 설정을 따르게 됩니다.
  • 이 설정 덕분에 SSL 인증서 검증을 건너뛰고 연결할 수 있게 됩니다.

5. HTTPS 연결 생성

HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
  • url.openConnection()은 지정된 URL로 연결을 시도합니다. 이때 url은 우리가 1번에서 만든 URL 객체입니다.
  • openConnection()은 연결을 만들고, 이를 HttpsURLConnection 객체로 캐스팅하여 conn에 할당합니다.
  • 이 연결은 SSL 인증서를 검증하지 않고, 모든 서버 인증서를 신뢰하는 설정을 따르게 됩니다.

핵심 요약:

  1. SSL 인증서 검증을 건너뛰기 위해 TrustManager를 커스터마이징하여 모든 인증서를 신뢰하도록 설정.
  2. SSLContext 객체를 사용해 기본 SSL 설정을 변경하고, 모든 HTTPS 연결에 대해 인증서 검증을 무시하도록 설정.
  3. HttpsURLConnection 객체를 통해 실제로 서버와 SSL/TLS 연결을 생성하되, 서버 인증서 검증을 하지 않음.

보안상의 위험:

  • SSL 인증서 검증을 생략하는 것은 중간자 공격(MITM)을 포함한 다양한 보안 위협에 노출될 수 있습니다. 실제 서비스에서는 서버 인증서를 반드시 검증해야 하며, 인증서 검증을 생략하면 악성 서버와 연결될 위험이 있습니다.
  • 신뢰할 수 없는 서버와 통신할 때만 사용할 것을 권장하며, 반드시 테스트 환경에서만 사용해야 합니다.

 

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class GsHttpsClient {

	public static void main(String[] args) {
		String urlStr = "https://www.google.com";
		
		StringBuffer sb = new StringBuffer();

		try {
			TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				public void checkClientTrusted(X509Certificate[] certs,
						String authType) {
				}

				public void checkServerTrusted(X509Certificate[] certs,
						String authType) {
				}
			} };

			SSLContext sc = SSLContext.getInstance("SSL");
			sc.init(null, trustAllCerts, new java.security.SecureRandom());
			HttpsURLConnection
					.setDefaultSSLSocketFactory(sc.getSocketFactory());

			URL url = new URL(urlStr);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			InputStreamReader in = new InputStreamReader(
					(InputStream) conn.getContent());
			BufferedReader br = new BufferedReader(in);

			String line;
			while ((line = br.readLine()) != null) {
				sb.append(line).append("\n");
			}

			System.out.println(sb.toString());
			br.close();
			in.close();
			conn.disconnect();

		} catch (Exception e) {
			System.out.println(e.toString());
		}
	}
}
반응형