如何从证书链、证书和私钥正确配置 HTTPS?阿卡HTTP

How to configure properly HTTPS from certificate chain, certificate and private key? Akka HTTP

简介

问题

尝试从网络浏览器发出 HTTPS GET 请求时:

Browser warning connection not secure

尝试向服务器 上的服务发出 cURL 请求时:

docker ps

端口

0.0.0.0:443->443/tcp

curl -v https://localhost

问题

如何正确配置 Akka HTTP 服务器以使用 HTTPS对于给定的:

到目前为止我做了什么?

  1. 我将 ca-certs 和 my-cert 连接到一个单独的 cert-chain.pem 文件中,并与私钥一起使用 openssl 创建了一个 p12 密钥库。
  2. 我写了下面的代码:
package de.htw_berlin.http

import java.security.SecureRandom
import akka.http.scaladsl.{ConnectionContext, HttpsConnectionContext}
import de.htw_berlin.security.{PKCS12KeyStoreFactory, X509KeyManagersFactory}

import java.io.FileInputStream
import javax.net.ssl.SSLContext

object HttpsConnectionContextFactory {

  // TODO refactor
  def apply(keyStoreFilename: String, keyStorePassword: String): HttpsConnectionContext = {
    val p12KeyStore = PKCS12KeyStoreFactory(new FileInputStream(keyStoreFilename), keyStorePassword)
    val sslContext: SSLContext = SSLContext.getInstance("TLS")
    sslContext.init(X509KeyManagersFactory(p12KeyStore, keyStorePassword), null, new SecureRandom)
    ConnectionContext.httpsServer(sslContext)
  }

}
package de.htw_berlin.security

import java.security.KeyStore

import javax.net.ssl.{KeyManager, KeyManagerFactory}

object X509KeyManagersFactory {

  def apply(keyStore: KeyStore, keyStorePassword: String): Array[KeyManager] = {
    val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
    keyManagerFactory.init(keyStore, keyStorePassword.toCharArray)
    keyManagerFactory.getKeyManagers
  }

}
package de.htw_berlin.security

import java.io.InputStream
import java.security.KeyStore

object PKCS12KeyStoreFactory {

  def apply(keyStoreAsInputStream: InputStream, keyStorePassword: String): KeyStore = {
    val p12KeyStore = KeyStore.getInstance("PKCS12")
    p12KeyStore.load(keyStoreAsInputStream, keyStorePassword.toCharArray)
    p12KeyStore
  }

}
package de.htw_berlin.http

import akka.actor.typed.ActorSystem
import akka.http.scaladsl.Http.ServerBinding
import akka.http.scaladsl.{Http, HttpsConnectionContext}
import de.htw_berlin.http.dip.RequestHandler

import scala.concurrent.Future

// TODO test.
/** Represents a HTTPS server which can be bind to a host and port.
 * The server needs a request handler for processing incoming requests.
 *
 * @param host         the optional host of the server. The default value is Constants.DefaultServerIpv4Address.
 * @param port         the optional port number of the server. The default value is Constants.DefaultHttpsPort.
 * @param httpsContext the https connection context for the https connection.
 * @param actorSystem  an implicit actor system.
 * @see de.htw_berlin.http.dip.RequestHandler
 */
class Server(val host: String = Constants.DefaultServerIpv4Address,
             val port: Int = Constants.DefaultHttpsPort,
             val httpsContext: HttpsConnectionContext)(implicit val actorSystem: ActorSystem[Nothing]) {

  /** Binds the current server to the endpoint parameters (host and port) and uses the passed
   * handler for processing incoming connections.
   *
   * @param handler the handler to be used for processing incoming requests.
   * @return a server binding future.
   */
  def bindAndHandleWith(handler: RequestHandler): Future[ServerBinding] =
    Http().newServerAt(host, port).enableHttps(httpsContext).bind(handler.getRoute)

}
package de.htw_berlin.http

/** This object contains constants related with the current module http. */
object Constants {

  /** The server's default IPv4 address. */
  val DefaultServerIpv4Address = "0.0.0.0"
  /** The default port for HTTPS connections. */
  val DefaultHttpsPort = 443

}

如果还不够,完整代码在我的publicrepository

我还做了什么

除了我阅读了很多关于 x509 标准和 TLS/HTTP 并在另一个线程中搜索答案的事实之外,我还检查了端口 443 在服务器上是否打开(顺便说一句:我在一个VPN 连接,所以防火墙应该无关紧要??)我向管理员求助,他不熟悉 Akka HTTP 和 docker,但他说 curl 输出可能与证书链有关。

您正在为此处的 TrustManager[] 参数传递 null

sslContext.init(X509KeyManagersFactory(p12KeyStore, keyStorePassword), null, new SecureRandom)

查看有关如何初始化和传递 TrustManager 的文档: https://doc.akka.io/docs/akka-http/current/server-side/server-https-support.html#using-https

令人尴尬的是,问题与 Docker 和使用 openssl 创建的密钥库有关:容器内的根用户没有读取密钥库的权限(权限被拒绝异常)。

但是,该代码有效,我会保留此线程作为社区的参考。

确保端口 443 已打开并且 运行

telnet localhost 443 看看有没有像 scape character is '^]'.

确保您的服务器使用 https 协议而不是 http

curl --insecure -v https://localhost 跳过 SSL 证书验证(但仍建立 SSL 连接)以查看您是否真的收到来自服务器的响应

确保您的服务器证书是全局签名的而不是自签名的

您的浏览器不信任未知证书,请确保您从全球 CA 获得 SSL 证书,例如让我们加密。您的浏览器有一个硬编码 CA 证书列表,用于验证每个网站的证书。

另一方面,您的 curl 正在 /etc/ssl/certs 中查找以获取用于验证您网站证书的 CA 证书列表,因此标志 --insecure 是跳过验证 SSL 证书。