簡體   English   中英

Scala:如何建立與PostgreSQL服務器的安全連接?

[英]Scala: How can I establish secure connection to PostgreSQL server?

我想使用基於JDBC的庫以編程方式在Scala中安全地連接到我的PostgreSQL服務器。 此外,我想以openssl生成的格式存儲所有SSL證書和密鑰文件( 不是由本機Java庫生成的KeyStore格式)。

我怎樣才能做到這一點?

我在用:

  • PostgreSQL 9.3
  • JVM 1.6
  • Scala 2.10.3

擴展作為PostgreSQL JDBC驅動程序一部分的org.postgresql.ssl.WrappedFactory類,然后將擴展類的名稱作為參數傳遞給setSslfactory()的相應子類的setSslfactory setSslfactory()方法。

假設您使用自簽名證書作為PostgreSQL服務器的證書( 注意 ,服務器的證書位於文件中,其名稱被指定為配置參數ssl_cert_file的值),並且

假設您將用於建立連接的PostgreSQL 登錄角色名為database_user

使用PostgreSQL服務器的證書簽署具有公用名( CN )屬性database_user的客戶端證書。 然后,使用客戶端計算機上的openssl PEM格式的服務器證書,客戶端證書和客戶端私鑰,以下內容將啟用到PostgreSQL服務器的安全,雙向身份驗證連接:

package mypackage

import org.postgresql.ssl.WrappedFactory

import org.bouncycastle.util.io.pem.PemReader

import java.io.{FileInputStream,FileReader}
import javax.net.ssl.{SSLContext,KeyManagerFactory,TrustManagerFactory}
import java.security.{KeyStore,KeyFactory,SecureRandom}
import java.security.cert.CertificateFactory
import java.security.spec.PKCS8EncodedKeySpec

object SocketFactory {
  final val PRIVATE_KEY_FILENAME = "private.key"
  final val CLIENT_CERT_FILENAME = "client.crt"
  final val SERVER_CERT_FILENAME = "/home/me/.ssl/postgres_server.crt"

  def certFromFile(fileName: String) =
    CertificateFactory getInstance "X.509" generateCertificate {
      new FileInputStream(fileName)
    }
}

class SocketFactory extends WrappedFactory {
  import SocketFactory._

  val sslContext = SSLContext getInstance "TLS"

  sslContext init (
    { // key managers: Array[KeyManager] 
      val kmf = KeyManagerFactory getInstance "SunX509"
      kmf init ({
        val keyStore = KeyStore getInstance KeyStore.getDefaultType
        keyStore load (null, null)
        keyStore setKeyEntry ( "",
          KeyFactory getInstance "RSA" generatePrivate (
            new PKCS8EncodedKeySpec (
              new PemReader (
                new FileReader(PRIVATE_KEY_FILENAME)
              ).readPemObject.getContent
            )
          ),
          Array[Char](), // no password for this entry
          Array(certFromFile(CLIENT_CERT_FILENAME))
        )
        keyStore
      }, Array[Char]())
      kmf.getKeyManagers
    },
    { // trust managers: Array[TrustManager]
      val tmf = TrustManagerFactory getInstance "PKIX"
      tmf init {
        val keyStore = KeyStore getInstance KeyStore.getDefaultType
        keyStore load (null, null)
        keyStore setCertificateEntry ("", certFromFile(SERVER_CERT_FILENAME))
        keyStore
      }            
      tmf.getTrustManagers
    },
    SecureRandom getInstance "SHA1PRNG"
  )

  _factory = sslContext.getSocketFactory

}

使用上述內容,您可以獲得如下所示的Java DataSource

def dataSource = {
  val ds = new PGSimpleDataSource
  ds.setDatabaseName("my_database")
  ds.setServerName("myHost.com")
  ds.setUser("database_user")
  ds.setSsl(true)
  ds.setSslfactory("mypackage.SocketFactory")
  ds
}

筆記:

  1. 此代碼不會捕獲任何異常,也不會關閉Streams / Readers。 根據需要修改。
  2. 此代碼不會根據服務器證書驗證客戶端證書,也不會根據客戶端證書驗證私鑰(超出連接嘗試次數)。 注意相關錯誤,並根據需要進行修改。
  3. 底層Java方法通常接受null作為有意義的參數。 如果您注意到奇怪的行為,請確保您不會在某處意外地傳遞null方法參數。
  4. 上述內容使用RSA密鑰對。 更新版本的openssl可以使用橢圓曲線加密。
  5. 要實現前向保密 ,請考慮在PostgreSQL配置中指定適當的密碼套件, 例如

    ssl_ciphers = 'DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA256-SHA'

其他文件

上面的示例在build.sbt文件中使用以下庫依賴build.sbt

libraryDependencies ++= Seq(
  "org.bouncycastle"   % "bcpkix-jdk15on" % "1.50",
  "org.postgresql"     % "postgresql"   % "9.3-1100-jdbc4"
)

您的pg_hba.conf文件需要一個適當的條目,如:

hostssl my_database database_user <client.ip.number>/32 trust clientcert=1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM