-
[spring][react][SSL] 인증서 발급하기금융프로젝트 2022. 10. 24. 10:59
Https와 SSL인증서
HTTP는 HTML을 전송하기 위한 통신규약이다. HTTPS는 데이터를 전송할 때 암호화를 사용하는 통신규약이다. HTTPS는 SSL프로토콜 위에서 돌아가는 프로토콜이다. SSL인증서는 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서다. 공인인증서가 그 예이다. SSL인증서를 통해 HTTPS서버로 접속할 수 있다.
CA
인증서의 역할은 클라이언트가 접속한 서버가 클라이언트가 의도한 서버가 맞는지 보장하는 역할을 한다. 이 역할을 하는 민간기업들이 있는데 이런 기업들을 CA라고 한다.
사설 인증기관
사설 CA의 인증서를 이용한다면 브라우저는 경고를 출력한다.
공인된 CA의 인증서를 사용한다면 경고를 출력하지 않는다.
프로세스
- 사용자 데이터 세팅
2. 사용자 신원 확인
따로 주민등록번호가 실제 주민등록번호인지 확인할 권한이 없으므로 아이디가 db에 존재한다면 인증서를 발급한다.
사용자는 id와 주민등록번호를 입력한다.
crt인증서와 개인키 파일이 C:/cert폴더에 생성된다.
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:\\\\cert\\\\temisone.key")); //비밀키 공개키 쌍 생성 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); KeyPair mKeyPair = kpg.genKeyPair(); os.writeObject(mKeyPair); os.close(); //crt인증서 생성 공급자는 temisone이다. X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator(); v3CertGen.setSerialNumber(new BigInteger("1234")); v3CertGen.setIssuerDN(new X509Principal("CN=temisone, OU=temisone, O=Company, L=Seoul, C=KR")); v3CertGen.setNotBefore(new Date()); v3CertGen.setNotAfter(new Date(System.currentTimeMillis()+1000L*60*60*24*365*10)); v3CertGen.setSubjectDN(new X509Principal("CN=temisone, OU=temisone, O=Company, L=Seoul, C=KR")); v3CertGen.setPublicKey(mKeyPair.getPublic());//키쌍의 공개키를 인증서에 저장한다. v3CertGen.setSignatureAlgorithm("SHA1withRSA"); //개인키로 인증서를 증명할 수 있도록 한다. X509Certificate pKCertificate = v3CertGen.generate(mKeyPair.getPrivate()); //로컬에 인증서와 키쌍을 저장한다. FileOutputStream fos = new FileOutputStream("C:\\\\cert\\\\temisone.crt"); fos.write(pKCertificate.getEncoded()); fos.close(); System.out.println("키저장완료");
3. 에러 처리
- 인증서가 이미 존재한다면
- 이미 인증서가 존재한다는 알림을 출력한다.
- 회원이 아니라면
- 아이디가 존재하지 않는다고 알림을 출력한다.
서버에 인증서 등록하기
현재까지 찾아본 바로는 수동으로 등록하는 방법뿐이었다.
- java
jdk나 jre는 keystore을 자체적으로 관리해서 인증서를 keystore에 등록할 수 있다. 경로는 jre/library/security/cacerts다.
docker 명령어로 키파일을 저장시킨다.
keytool -import -keystore [키스토어 경로] -file [키파일 경로]
tomcat서버에 keystore를 등록해준다.
server.xml
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" defaultSSLHostConfigName="localhost"> <SSLHostConfig hostName="localhost" protocols="TLSv1.2,+TLSv1.1,+TLSv1"> <Certificate certificateKeystoreFile="C:\\java_hyj\\jre\\bin\\temisoneKeyfile" type="RSA" certificateKeystorePassword="temisone1245"/> </SSLHostConfig> </Connector>
이렇게 하면 인증서를 가지고 https접속이 된다.
동적으로 키파일이 keystore에 존재하는지 검증할 수 있다.
public class HttpsURLConnection { static String urlString= "<https://localhost:443>"; static String line = null; static InputStream in = null; static BufferedReader reader = null; static javax.net.ssl.HttpsURLConnection httpsConn = null; public HttpsURLConnection() throws IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, UnrecoverableKeyException { URL url = new URL(urlString); httpsConn = (javax.net.ssl.HttpsURLConnection) url.openConnection(); // Set Hostname verification httpsConn.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { // Ignore host name verification. It always returns true. return true; } }); // Input setting httpsConn.setDoInput(true); // Output setting //httpsConn.setDoOutput(true); // Caches setting httpsConn.setUseCaches(false); // Read Timeout Setting httpsConn.setReadTimeout(1000); // Connection Timeout setting httpsConn.setConnectTimeout(1000); // Method Setting(GET/POST) httpsConn.setRequestMethod("GET"); // Header Setting httpsConn.setRequestProperty("HeaderKey","HeaderValue"); //로컬의 키파일을 가져온다. KeyStore clientStore = KeyStore.getInstance("jks"); clientStore.load(new FileInputStream("C:/cert/temisone.crt"),"temisone1245".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(clientStore,"temisone1245".toCharArray()); KeyManager[] kms = kmf.getKeyManagers(); //서버의 키스토어를 가져온다. KeyStore trustStore = KeyStore.getInstance("jks"); trustStore.load(new FileInputStream("C:/java_hyj/jre/lib/security/cacerts"),"temisone1245".toCharArray() ); //사설 인증서를 인증해주지 않아서 무조건 인증을 사용한다. TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); 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 sslContext = null; sslContext = SSLContext.getInstance("TLS"); sslContext.init(kms, trustAllCerts,new SecureRandom()); httpsConn.setSSLSocketFactory(sslContext.getSocketFactory()); System.out.println("끝"); httpsConn.connect(); httpsConn.setInstanceFollowRedirects(false); } }
- react
react도 자체적인 서버를 가지기 때문에 https인증을 해주어야 한다.
mkcert를 사용하여 key를 등록해준다
mkcert -key-file [개인키 경로] -cert-file [인증서 경로]
package.json에 사용할 인증서를 등록해준다.
"scripts": { "start": "cross-env HTTPS=ture SSL_CRT_FILE=C:/cert/temisone.crt react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" },
아쉬운점
자체적으로 발급한 인증서라 두가지 방법을 사용해도 제대로 인증이 되지 않는다.
시연 영상
'금융프로젝트' 카테고리의 다른 글
[react][슬라이드] 3초마다 화면이 변경되는 슬라이드 구현 (0) 2022.10.27 [react][spring]로그인 페이지 (0) 2022.10.25 [spring][java][bouncycastle] 인증서 발급하기 (0) 2022.10.20 [spring][https][security][jks] 스프링 프로젝트 https로 만들기 (0) 2022.10.19 [spring][myBatis][RDS][mariaDB] 프로젝트 초기 세팅 (0) 2022.10.19