본문 바로가기
Stack Overflow/스프링

[스프링] SSL API 통신 시 SSLHandshakeException & CrossDomain ERROR 오류에 대한 대응을 위한 코딩방법

by Lich King 2021. 12. 21.

크롬 브라우저에서 보안 강화 정책으로 이제 다른 도메인과 통신을 지행할 때, SSL 검증을 진행하여 동일한 도메인이 아닌 경우 통신오류를 발생시킨다.
즉, 이전과 다르게 SSL 통신 루틴을 처리해주지 않으면 SSLHandshakeException 또는 CrossDomain 오류를 발생시킨다.
따라서 인증서와 관련된 SSL 이슈 대응은 매우 중요하며, 전체적인 공통 클래스로 만들어놓고 다른 도메인과의 API 통신 시 SSL을 처리를 기본적으로 해줘야 한다.
다음은 스프링에서 SSL API 통신에 대해 기술한다.

1. 요약
1.1 jks 인증서 파일을 준비하여 프로젝트에 적절히 위치 시킨다.
1.2 공통 SSL 메소드를 RestTemplate 클래스를 동시에 초기화 한다.
1.3 API 데이터 교환을 시행한다.

2. SSL  처리 데이터 공통 파일

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;

private TrustStrategy trustStrategy = new TrustStrategy() {
	@Override
	public boolean isTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) {
		return true;
	}
};

private HttpComponentsClientHttpRequestFactory getBaseRequestFactory() throws Exception {
	String CERT_KEY_NAME = "실제 jks 파일명";
	String CERT_KEY_PASSWORD = "비밀번호";

	ClassPathResource resource = new ClassPathResource(CERT_KEY_NAME);
	KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

	keyStore.load(new FileInputStream(resource.getFile()), CERT_KEY_PASSWORD.toCharArray());

	SSLContext sslcontext = SSLContexts.custom().useProtocol("SSL").loadTrustMaterial(null, trustStrategy)
			.loadKeyMaterial(keyStore, CERT_KEY_PASSWORD.toCharArray()).build();

	SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);

	CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();

	HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
	requestFactory.setHttpClient(httpClient);
	return requestFactory;
}


CERT_KEY_NAME 변수에서는 jks 인증서 확장자로서, 파일명을 확장자까지 포함하여 기입을 해준다.
CERT_KEY_PASSWORD 변수는 jks 인증서 비밀번호를 입력해준다.
상기 파일을 공통부분으로 임의로 가공을 하여 전체 프로젝트에서 유용하게 쓸 수 있도록 개발을 진행하면 된다.

3. 통신 임의 VO 파일

/**
* VO CLASS 파일
*/
public class AnnotJsonPropVo {
    @JsonProperty("test")
    private String test;

    public void setTest(String test) {
	this.test = test;
    }

    public String getTest() {
	return test;
    }
}


통신할 API 양식에 맞추어 클래스 파일을 만들어준다.

상기 파일은 샘플이기 때문에 필요한 VO로 변경하면 된다.

4. API REST 통신 진행

RestTemplate restTemplate = new RestTemplate(getBaseRequestFactory());

HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
headers.add("Accept-Charset", "UTF-8");
headers.add("Authorization", "HTTP 권한키");	
	
AnnotJsonPropVo mainParam = new AnnotJsonPropVo();
	
//@JsonProperty VO 클래스 파일
HttpEntity<AnnotJsonPropVo> httpEntity = new HttpEntity<AnnotJsonPropVo>(mainParam, headers);
try {
    AnnotJsonPropVo entity = restTemplate.postForObject("API CALL URL", httpEntity,AnnotJsonPropVo.class);
}
catch(HttpStatusCodeException e) {
}
catch (Exception e) {
}


초기화 할때 초기에 SSL 파일 공통을 RestTemplate 클래스에 삽입하여 초기화를 진행해주는 것이 중요하다.
이어 REST 통신을 진행하기 위해 restTemplate.postForObject 클래스를 호출하고 RETURN 값이 NULL이 아닌 경우 정상적으로 처리가 완료 된 것이다.
만약에 정상적으로 통신이 되지 않은 경우 SSL 처리가 잘못되었거나 VO클래스 파일을 확인해줘야 한다.

크롬에서 SSL CrossDomain을 체크를 진행하면서 상기와 같이 개발을 진행하였고, 이를 기록하였음.

이런식으로 처리를 진행하면 SSLHandshakeException 와 같은 에러는 안나오고 정상적으로 통신이 된다.

인증서 파일 유효기간도 확인을 잘하는 것이 중요하다.

댓글