programing

SSL(자기서명) 증명서를 사용하여 스프링 및 휴지기를 통해 MariaDB 연결

nicescript 2022. 10. 30. 15:37
반응형

SSL(자기서명) 증명서를 사용하여 스프링 및 휴지기를 통해 MariaDB 연결

Spring과 Hibernate를 탑재한 J2EE 어플리케이션을 개발했습니다.이제 SSL 증명서를 사용하여 애플리케이션을 MariaDB에 연결하려고 합니다(비밀번호를 사용하지 않음). 다음 명령을 사용하여 데이터베이스에 연결할 수 있습니다.

mysql -h myhost.com -P3306 -umyuser --ssl-ca ca.crt --ssl-cert app.crt --ssl-key my-key.pem

그러나 다음 오류가 발생하여 내 응용 프로그램을 데이터베이스에 연결할 수 없습니다.

에러 로그

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    at com.mysql.jdbc.Util.getInstance(Util.java:381)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
    at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2270)
    at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:723)
    at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:46)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:302)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:282)
    at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:146)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:195)
    at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:184)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:200)
    at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1086)
    at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1073)
    at com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:44)
    at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1810)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:648)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

Last packet sent to the server was 71 ms ago.
    at sun.reflect.GeneratedConstructorAccessor37.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1074)
    at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:104)
    at com.mysql.jdbc.MysqlIO.negotiateSSLConnection(MysqlIO.java:4502)
    at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1322)
    at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2198)
    ... 18 more
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:89)
    ... 21 more

질문을 읽은 후 다음 명령을 사용하여 인증서를 키 저장소에 추가했습니다.

keytool -import -noprompt -trustcacerts -alias "My App Certificate" -file ca.crt -keystore /usr/lib/jvm/java-1.6.0-openjdk/jre/lib/security/cacerts -storepass mypassword

여전히 다음 오류가 발생하며 다음 오류는 구성 파일입니다.

JDBC.properties

jdbc.initialPoolSize=10
jdbc.maxPoolSize=30
jdbc.minPoolSize=5
jdbc.acquireIncrement=3
jdbc.acquireRetryAttempts=0
jdbc.preferredTestQuery=SELECT 1
jdbc.idleConnectionTestPeriod=600
jdbc.numHelperThreads=10
jdbc.debugUnreturnedConnectionStackTraces=true
jdbc.mydbUrl=jdbc:mysql://myhost.com:3306/mydb?verifyServerCertificate=true&useSSL=true&requireSSL=true&characterEncoding=utf8
jdbc.mydbUsername=myuser

datasource-timeout.xml

<bean id="mydbCommon" class="com.mchange.v2.c3p0.ComboPooledDataSource" abstract="true" destroy-method="close">
    <property name="driverClass" value="${jdbc.rptdbDriverClassName}"/>
    <!-- Common properties for all DS -->
        <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
        <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
        <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
        <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>
        <property name="preferredTestQuery" value="${jdbc.preferredTestQuery}"/>
        <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
        <property name="numHelperThreads" value="${jdbc.numHelperThreads}"/>
        <property name="debugUnreturnedConnectionStackTraces" value="${jdbc.debugUnreturnedConnectionStackTraces}"/>
</bean>
<bean id="mydb" parent="mydbCommon">
        <property name="jdbcUrl" value="${jdbc.mydbUrl}"/>
        <property name="user" value="${jdbc.mydbUsername}"/>
</bean>

이 문제를 해결할 수 있는 사람은 누구입니까?잘 부탁드립니다...

다음은 제가 문제를 해결하기 위해 따라야 할 단계입니다. 이것은 저의 창의성이 아닙니다. 단지 다음 기사에서 언급된 몇 가지 단계를 모으세요.

레퍼런스

SSL을 사용한 안전한 연결

가장 일반적인 OpenSSL 명령어

SSL 암호화를 사용하여 데이터베이스에 연결하려면 다음이 필요합니다.

  • MySQL 서버가 SSL 연결을 허용하도록 구성하기 위한 데이터베이스 관리자의 지원입니다.
  • 서버의 암호화 키에 대응하는 SSL PEM 공개 키 파일.

MySQL 서버가 SSL을 지원하는지 확인하는 단계

다음 명령을 사용하여 서버가 SSL을 지원하는지 확인합니다.

show variables like 'have_ssl'

서버로부터의 답변이 다음과 같은 경우

아니요. 그러면 서버에는 SSL 지원이 컴파일되지 않습니다.사용 안 함. 시스템 관리자가 SSL을 사용하도록 설정한 상태에서 MySQL 서버를 시작하지 않습니다., SSL을 사용할 수 있습니다.

MySQL for SSL을 구성하지 않으려면 MySql 문서를 따르십시오.

6.3.6.2 SSL용 MySQL 설정

JDBC와 함께 서버의 SSL 인증서를 사용하도록 Java 환경을 구성하려면 다음 단계를 수행하십시오.

시스템은 2개의 Java 트러스트 스토어 파일을 통해 동작합니다.

  • 1개의 파일에는 서버의 증명서 정보가 포함되어 있습니다(아래 예에서는 신뢰 스토어).
  • 다른 파일에는 클라이언트의 증명서가 포함되어 있습니다(아래 예에서는 키스토어).

메모: 모든 Java 트러스트 스토어 파일은 파일을 작성할 때 키 도구에 적절한 비밀번호를 입력하여 비밀번호로 보호됩니다.SSL 연결을 만들려면 파일 이름과 관련 암호가 필요합니다.

신뢰 저장소 파일을 만듭니다.

먼저 MySQL 서버 CA 증명서를 Java 신뢰 스토어로 Import해야 합니다.MySQL 원본 배포의 SSL 하위 디렉터리에 MySQL 서버 CA 인증서 샘플이 있습니다.이것은 SSL이 사용자가 안전한 MySQL 서버와 통신하고 있는지 여부를 판단하기 위해 사용하는 것입니다.또는 SSL 공급자가 생성했거나 제공한 CA 인증서를 사용합니다.

메모: 키툴이 경로에 있다고 가정합니다.일반적으로 키툴은 JDK 또는 JRE의 bin 서브디렉토리에 있습니다.

shell> keytool -import -alias dbServerCACert -file ca.crt -keystore truststore
    Enter keystore password: truststorepwd 
    Re-enter new password: truststorepwd
    ....    
    Trust this certificate? [no]:  yes
    Certificate was added to keystore

Keystore 파일을 만듭니다.

우선 다음 명령을 사용하여 빈 Java 키스토어 파일을 생성해야 합니다.

shell>keytool -genkey -alias dbkeystore -keystore my-app.jks
    Enter keystore password:  
    Re-enter new password: 
    What is your first and last name?
      [Unknown]:  mycomp
    What is the name of your organizational unit?
      [Unknown]:  mycomp
    What is the name of your organization?
      [Unknown]:  mycomp
    What is the name of your City or Locality?
      [Unknown]:  Singapore
    What is the name of your State or Province?
      [Unknown]:  Singapore
    What is the two-letter country code for this unit?
      [Unknown]:  SG
    Is CN=mycomp , OU=mycomp, O=mycomp, L=Singapore, ST=Singapore, C=SG correct?
      [no]:  yes

    Enter key password for <keystore>
        (RETURN if same as keystore password):

    shell>keytool -delete -alias dbkeystore -keystore my-app.jks
    Enter keystore password: keystorepwd

다음 명령을 사용하여 클라이언트 인증서(my-app.crt) 및 개인 키(my-app.key)를 pkcs12 파일로 변환합니다.

shell>openssl pkcs12 -export -name dbkeystore -in my-app.crt -inkey my-app.key -out my-app.p12
    Enter Export Password: keystorepwd 
    Verifying - Enter Export Password: keystorepwd

다음 명령을 사용하여 p12 파일을 keystore로 Import합니다.

keytool -importkeystore -destkeystore my-db.jks -srckeystore my-app.p12 -srcstoretype pkcs12 -alias dbkeystore

JVM 검증 가능 설정

마지막으로 생성한 키스토어와 신뢰스토어를 사용하려면 JVM의 다음 시스템 속성을 설정해야 합니다.

-Djavax.net.ssl.keyStore=/path/to/my-app.jks
-Djavax.net.ssl.keyStorePassword=keystorepwd
-Djavax.net.ssl.trustStore=/path/to/truststore
-Djavax.net.ssl.trustStorePassword=truststorepwd

SSL을 지원하도록 연결 URL 업데이트

또한 URL에 useSSL=true를 추가하여 MySQL Connector/J의 연결 매개 변수에서 useSSL을 true로 설정해야 합니다.

jdbc:mysql://<HOST>:<PORT>/DB?verifyServerCertificate=true&useSSL=true&requireSSL=true

테스트 응용 프로그램을 실행하여 모든 파일이 작동하는지 확인합니다.

static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://<HOST>:<PORT>/DB?verifyServerCertificate=true&useSSL=true&requireSSL=true"
    public static void main(String[] args) {    
        Connection conn = null;
        try {
            Class.forName(JDBC_DRIVER);
            // STEP 3: Open a connection
            System.out.println("Connecting to database...");
            conn = DriverManager.getConnection(DB_URL);
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                }
            }
        }
    }

이 절차가 도움이 되길 바랍니다…!

언급URL : https://stackoverflow.com/questions/24402237/connect-mariadb-through-spring-and-hibernate-using-ssl-self-signed-certificate

반응형