HOWTO: JDBC over an SSH Tunnel


First, credit where credit is due. Most of this code came from here (I just modified it a bit):

http://www.miranet.ch/posts/2008/09/23/howto_jdbc_over_ssh/

You’ll also need JSch (a java implementation of SSH):

http://www.jcraft.com/jsch/

The major function of SSH tunnels are to secure what would otherwise be an unsecure client/server connection. But another awfully handy use of SSH tunnels are accessing remote resources that are not normally exposed. Databases, for example.

I recently needed to access a MySQL database on a remote server from some local Java code. This database is off on a third party hosting server that does not allow outside access to MySQL, but I can login via SSH.

So, here goes:

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class CTestDriver
{
  private static void doSshTunnel( String strSshUser, String strSshPassword, String strSshHost, int nSshPort, String strRemoteHost, int nLocalPort, int nRemotePort ) throws JSchException
  {
    final JSch jsch = new JSch();
    Session session = jsch.getSession( strSshUser, strSshHost, 22 );
    session.setPassword( strSshPassword );
    
    final Properties config = new Properties();
    config.put( "StrictHostKeyChecking", "no" );
    session.setConfig( config );
    
    session.connect();
    session.setPortForwardingL(nLocalPort, strRemoteHost, nRemotePort);
  }
  
  public static void main(String[] args)
  {
    try
    {
      String strSshUser = "ssh_user_name";                  // SSH loging username
      String strSshPassword = "abcd1234";                   // SSH login password
      String strSshHost = "your.ssh.hostname.com";          // hostname or ip or SSH server
      int nSshPort = 22;                                    // remote SSH host port number
      String strRemoteHost = "your.database.hostname.com";  // hostname or ip of your database server
      int nLocalPort = 3366;                                // local port number use to bind SSH tunnel
      int nRemotePort = 3306;                               // remote port number of your database 
      String strDbUser = "db_user_name";                    // database loging username
      String strDbPassword = "4321dcba";                    // database login password
      
      CTestDriver.doSshTunnel(strSshUser, strSshPassword, strSshHost, nSshPort, strRemoteHost, nLocalPort, nRemotePort);
      
      Class.forName("com.mysql.jdbc.Driver");
      Connection con = DriverManager.getConnection("jdbc:mysql://localhost:"+nLocalPort, strDbUser, strDbPassword);
      con.close();
    }
    catch( Exception e )
    {
      e.printStackTrace();
    }
    finally
    {
      System.exit(0);
    }
  }
}

So, now I can access the remote database and the traffic is encrypted on top of that!

Same disclaimer as always, this IS NOT production worthy code as is. The exception handling is crap and there’s lots more paranoia to be had. Please follow your own coding best-practices.


Leave a Reply