How to implement Secure Connection to SAP HANA Database through JDBC? - java

I am able to connect to HANA database through my server using JDBC. I am trying to figure out if my connection to the database is secured or not?
public void createDataSource() {
DataSource dataSource = DataSourceBuilder.create()
.driverClassName(JDBC_DRIVER)
.URL("jdbc:sap://localhost:30013/?encrypt=true&validateCertificate=true")
.username("username")
.password("password")
.build();
Connection c = dataSource.getConnection();
}
Now what I have understood from Documentation is that when I set parameters in the URL such
encrypt=true
It enables or disables TLS encryption.
For SAP HANA Cloud connections to succeed, encrypt must be set to TRUE.
Another parameter is:
validateCertificate=true
If set to true, specifies that the server’s certificate is validated.
Here I am not able to understand is when it will be deployed to production is this all we need to do for a secure database connection? Can someone please point out what I am missing?

The neat thing about certificates is that you normally don't have to worry about them.
The java virtual machine (JVM) ships with a set of so-called root certificates of the certificate authorities (CAs) (including the DigiCert Global Root CA). Depending on the java distribution there might be slight differences, but the top CAs should be trusted by all.
You can see the list of trusted CAs with the following command:
keytool -list -v -cacerts -storepass changeit
As long as the SSL certificate of your database is signed by one of these CAs (or an intermediate of these) you don't need any additional configuration and it just works out of the box. This is as well the scenario, which you should aim for as it is the easiest.
You can however as well pass to the JVM your own list of trusted certificates or, and this is probably for a generic set up the best, set a custom truststore for a single JDBC connection. In a dockerized setup, you can e.g. make the whole database string configurable allowing people to mount their own CAs into the container and configure them in the database connection string. For details check the SAP documentation on the "JDBC Connection Properties for SAP HANA".
jdbc:sap://localhost:30013/?encrypt=true&validateCertificate=true&trustStore=file:cert/truststore.jks&trustStorePassword=123456

Related

Provide SSL certificate to SQL Server via JDBC

The Microsoft JDBC SSL documentation details the use of a Java keystore in order to specify a certificate bundle to use when validating the TLS connection. Is there a way to provide a certificate bundle without needing to store it within a JKS when connecting to a SQL Server database? Postgres seems to have a sslrootcert option which appears to be lacking for SQL Server.
Since version 6.3.3 the Microsoft JDBC Driver for SQL allows, to specify a custom implementation of javax.net.ssl.TrustManager through connection properties. You can specify a class name and a constructor parameter (e.g. a file name or the certificate in PEM format).
See here, for more detailed instructions and a simple example of a custom TrustManager. The functionality of the sslrootcert option of the Postgres driver is implemented in a similar way here.

Postgresql JDBC SSL

We have a remote PostgreSQL DB server which requires SSL certs to be provided to connect to it.
I have the following certs with me.
root.pem
intermediate.pem
private-chain.pem
public-chain.pem
certificate.cer
certificate.key
And I am able to connect to the remote database using psql as
psql "port=5432 host=remote-host user=username sslcert=public-chain.pem sslkey=certificate.key dbname=database sslmode=require"
Now, I need to connect to the same database from a Java Spring based Rest API. So, ideally this would require building keystrokes from the certs and using that to connect to the the db.
The issue is, I'm not able to! I've tried all combinations of cert, public-chain, private-chain, root ca, etc. in the keystore. And I've tried passing the keystore as JVM arguments when calling the jar file (-Djavax.net.ssl.trustStore -Djavax.net.ssl.trustStorePassword -Djavax.net.ssl.keyStore -Djavax.net.ssl.keyStorePassword).
I've also tried pointing to the keystrokes from PostgreSQL JDBC connection string (jdbc:postgresql://remote-host:5432/database?ssl=true&sslcert='filename'&sslkey='key'). Not really sure if this is the right way.
But I keep getting this error.
Caused by: org.postgresql.util.PSQLException: FATAL: connection requires a valid client certificate
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:473) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:205) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.Driver.makeConnection(Driver.java:452) ~[postgresql-42.2.2.jar!/:42.2.2]
at org.postgresql.Driver.connect(Driver.java:254) ~[postgresql-42.2.2.jar!/:42.2.2]
I am not able to figure out why it works with psql and not with jdbc.
EDIT 1:
Currently I am trying the following approach. This is the spring datasource configuration
spring.datasource.url=jdbc:postgresql://remote-host:5432/database?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
spring.datasource.username=username
This is the cert config
export PGSSLCERT=/tmp/client.cer
export PGSSLKEY=/tmp/client.key
export PGSSLMODE=allow
I've also followed the steps described here to trust root ca. But I guess that is not necessary since I'm using org.postgresql.ssl.NonValidatingFactory
And I'm starting the application as
java -jar -Dspring.profiles.active=prod application.jar
Any insights into this are appreciated! Thanks.
What does your pb_hba.conf setting look like?
The JDBC driver only supports the trust, ident, password, md5, and crypt authentication methods.
So your java app will have to connect using password and certificate. You can specify that in your pb_hba.conf:
hostssl all all 0.0.0.0/0 md5 clientcert=1

Why can JDBC connect to MySQL when SSL has been configured, without having the cert

My issue is I seem to have secured MySQL from the command line, yet when I connect through JDBC that same restriction falls away. I'm a beginner to using SSL for my database connection, this is the first time I've tried to set it up.
I setup SSL for MySQL locally on my Linux machine. I generated the certificates, editing my.cnf, etc.
Here is what I added to my my.cnf:
[mysqld]
ssl-ca=/var/lib/mysql/cert/ca-cert.pem
ssl-cert=/var/lib/mysql/cert/server-cert.pem
ssl-key=/var/lib/mysql/cert/server-key.pem
Right there are valid paths to my server cert/key, and my CA cert. It's self-signed. I'll get to having a more official one when I need it.
In the MySQL database, I set my database user account to require SSL:
GRANT ALL PRIVILEGES ON *.* TO ‘orgapi’#’localhost’
IDENTIFIED BY ‘password’ REQUIRE SSL;
So far so good. Once that user requires SSL, MySQL seems to require a client cert to be provided when making the connection. I generated that cert as well, signing it with the same self-signed CA cert.
Now, for the first test: I tried logging in from the command line WITHOUT the client cert:
mysql -u orgapi -p -h localhost
Voila, it fails to let me log in. However, when I include the SSL cert in the login command, like this:
mysql --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem -u orgapi -p -h localhost
It works like a charm. I'm able to connect when I specify the client cert, and if I do a "status" command, it says I'm connected using SSL.
The problem
To ensure that everything was all set to go, I threw together some basic test code using JDBC. Currently, I'm not providing the client certs to this JDBC code. Because of that, I would expect the connection to fail.
public static void main(String[] args) throws Exception{
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306", "orgapi", "orgapi");
conn.setCatalog("org_app");
Statement stmt = conn.createStatement();
ResultSet resultSet = stmt.executeQuery("select * from users");
while(resultSet.next()){
System.out.println(resultSet.getString(1) + " " + resultSet.getString(2));
}
}
What worries me is that it doesn't fail. In fact, it executes the query without any issue. Now, if I append to the end of the database url "?useSSL=true", then it will fail to connect because it doesn't have the cert. But it still concerns me that JDBC code would be able to connect to MySQL and bypass the restrictions that exist elsewhere.
So I'm just wondering what I may be doing wrong, or what I don't understand about this process. I just want to be sure that I'm not leaving my database less secure somehow.
Edit
I do get this interesting log message when I'm using JDBC:
Sun Oct 23 08:58:28 EDT 2016 WARN: Establishing SSL connection without
server's identity verification is not recommended. According to MySQL
5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance
with existing applications not using SSL the verifyServerCertificate
property is set to 'false'. You need either to explicitly disable SSL
by setting useSSL=false, or set useSSL=true and provide truststore for
server certificate verification.

How to use the Windows Keystore (MCS) with JDBC?

I am trying to create a java application that uses PKI for authentication. I need to be able to retrieve a certificate from the Microsoft Certificate Store (MCS) and pass it along to an Oracle database (11.2).
I am connecting using the jdbc:oracle:thin driver. After spending quite some time on google I have come up empty.
I've found different properties to change (depending on the article):
set the property javax.net.ssl.keyStoreType = "Windows-MY"
set the javax.net.ssl.keyStore = "Windows-MY"
javax.net.ssl.keyStore should be set to "None" (if using a custom KeyManager which I do not believe will work since by the time it gets into my custom KeyManager I will already be given the certs from a keystore specified in the connection properties).
Of course all of these people are claiming success, but nothing has worked for me. I have tried every example I have been able to find all with no luck. I was able to successfully authenticate when I was using Oracle wallets so I know my certificates are fine. If anyone has done this before and is willing to post some code that would be great.
I know most people are using the Windows keystore with a website and therefore are creating their own SSLContext, but I cannot imagine I am the only one who has wanted to do this using JDBC (which as far as I know does not allow me to provide it an SSLContext).
This is the code that I believe should work, but does not.
DriverManager.registerDriver)new OracleDriver());
String url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=host)(PORT=2484))(CONNECT_DATA=(SERVICE_NAME=someName))(SECURITY= (SSL_SERVER_CERT_DN=\"CN=TESTSERVER\")))";
java.util.Properties props = new java.util.Properties();
props.setProperty("javax.net.ssl.keyStoreType", "Windows-MY");
props.setProperty("javax.net.ssl.keyStore", "NONE");
props.setProperty("javax.net.ssl.trustStoreType", "Windows-ROOT");
props.setProperty("javax.net.ssl.trustStore", "NONE");
props.setProperty("oracle.net.ssl_server_dn_match", "true");
props.setProperty("oracle.net.authentication_services", "(TCPS)");
Connection conn = DriverManager.getConnection(url, props);
This code fails with the exception:
java.sql.SQLRecoverableException: IOException: The Network Adapter could not establish the connection
This article should give your more details. Although it doesn't use the system properties, Windows-MY is clearly a store type and it's not file based. Therefore, javax.net.ssl.keyStoreType should be Windows-MY and javax.net.ssl.keyStore should be set to NONE (upper case may matter), see the JSSE Ref Guide (Customization):
javax.net.ssl.keyStore system property
Note that the value NONE may be specified. This setting is appropriate if the keystore is not
file-based (for example, it resides in a hardware token).
You may also need to configure your trust store in a similar way if your server certificate isn't trusted by your default Java trust store.

Mirth: calling an SSL SOAP web service with a client certificate

The scenario is around calling an external SSL SOAP web service from within Mirth. The web service is requires an SSL/TLS connection along with a client certificate.
The intention is to use the built-in SOAP Sender Destination to call the remote secure web service, and somehow include that client certificate.
I understand that you first need to install that client certificate into the Java runtime. This may be within the Java runtime's certificate store or the Jetty certstore.
The platform:
Windows 2003 SP2
Mirth 1.8
Java jre1.5.0_09
Question: what configuration steps (Mirth, JRE certificate stores, etc.) would you suggest to successfully have a Mirth SOAP Sender include a client certificate (*.cer) when calling a web service secured by SSL?
The Java runtime, or more specifically, the Sun JSSE provider, will present a client certificate if some system properties are set. You can read details in the JSSE Reference Guide, but the important properties are javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword.
There are a few drawbacks to this approach. First, setting the key store password as a system property makes it accessible to any code running in that process—although this can be controlled if a SecurityManager is installed. Second, these settings will be used for any SSL sockets created through the "default" SSLContext. If you need different credentials for different endpoints, you'll need a Mirth-specific solution.
No starting point was specified in the question, but if starting from scratch, the easiest approach is to create a new Java Key Store ("JKS" format) and generate a new key pair and a CSR. After sending the CSR to the CA and getting a certificate back, import it into the same key store. That key store is ready to use.
If a certificate is already available, it is likely to be in a stored with its corresponding private key in PKCS #12 format (.p12 or .pfx file). These can be used directly by a Java application, but the javax.net.ssl.keyStoreType property will need to be set to "PKCS12"
Mirth 1.8 cannot send a client cert when calling a SOAP web service.
I'm late a bit here for this but actually there is a possibility that it could. By sending a few config parameters to the JVM you could get the underlying SOAP engine to switch to HTTPs and provide the proper certificate.
refer to this question for details on which parameters to set for configuring the VM
Java HTTPS client certificate authentication
you will notice there are quite a few things to take care of. Normally HTTPs and client authentication should "just work" once you configured your certificates appropriately. BUT there are some servers out there that are not so friendly to B2B style clients so you have to watch out.
Using JDK 6_21 and a few tweaks with the certificate I was able to get one of them servers to behave but it was long and painful on our side for something that takes about 15 minutes to configure properly on the server.
here is another question that address this very issue (client side authentication towards unfriendly servers).
Client SSL authentication causing 403.7 error from IIS

Categories