Skip to content
Server Plugin

Ktor 服务器中的 SSL 和证书

所需依赖项: io.ktor:ktor-network-tls-certificates

代码示例: ssl-engine-main, ssl-embedded-server

在大多数情况下,你的 Ktor 服务位于反向代理(例如 Nginx 或 Apache)之后。这意味着反向代理服务器会处理安全问题,包括 SSL。

如果需要,你可以通过提供证书路径来配置 Ktor 直接提供 SSL 服务。Ktor 使用 Java KeyStore (JKS) 作为证书的存储设施。你可以使用 keytool 来转换和管理存储在 KeyStore 中的证书。如果你需要将证书颁发机构颁发的 PEM 证书转换为 Ktor 支持的 JKS 格式,这可能会很有用。

你可以使用 Let's Encrypt 获取免费证书,以便 Ktor 服务 https://wss:// 请求。

生成自签名证书

通过代码生成证书

Ktor 提供通过调用 buildKeyStore 函数来生成自签名证书以供测试目的的能力,该函数返回一个 KeyStore 实例。要使用此函数,你需要在构建脚本中添加 ktor-network-tls-certificates 构件:

Kotlin
Groovy
XML

以下代码片段展示了如何生成证书并将其保存到密钥库文件:

kotlin
private fun ApplicationEngine.Configuration.envConfig() {

    val keyStoreFile = File("build/keystore.jks")
    val keyStore = buildKeyStore {
        certificate("sampleAlias") {
            password = "foobar"
            domains = listOf("127.0.0.1", "0.0.0.0", "localhost")
        }
    }
    keyStore.saveToFile(keyStoreFile, "123456")
}

由于 Ktor 在启动时需要证书,你必须在启动服务器之前创建证书。你可以在此处找到完整示例:ssl-embedded-server

使用 keytool 生成证书

你可以使用 keytool 生成自签名证书:

Bash
keytool -keystore keystore.jks -alias sampleAlias -genkeypair -keyalg RSA -keysize 4096 -validity 3 -dname 'CN=localhost, OU=ktor, O=ktor, L=Unspecified, ST=Unspecified, C=US'

执行此命令后,keytool 会建议你指定密钥库密码,然后生成一个 JKS 文件。

将 PEM 证书转换为 JKS

如果你的证书颁发机构颁发 PEM 格式的证书,则需要在 Ktor 中配置 SSL 之前将其转换为 JKS 格式。你可以使用 opensslkeytool 工具来完成此操作。例如,如果你的私钥在 key.pem 文件中,公钥证书在 cert.pem 中,则转换过程可能如下所示:

  1. 使用 openssl 通过以下命令将 PEM 转换为 PKCS12 格式:

    Bash
    openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12 -name "sampleAlias"

    系统将提示你输入 key.pem 的密码短语和 keystore.p12 的新密码。

  2. 使用 keytool 将 PKCS12 转换为 JKS 格式:

    Bash
    keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks

    系统将提示你输入 keystore.p12 文件的密码和 keystore.jks 的新密码。keystore.jks 将被生成。

在 Ktor 中配置 SSL

在 Ktor 中指定 SSL 设置取决于用于 配置 Ktor 服务器 的方式:通过配置文件或通过代码使用 embeddedServer 函数。

配置文件

如果你的服务器是在 application.confapplication.yaml 配置文件 中配置的,你可以使用以下 属性 启用 SSL:

  1. 使用 ktor.deployment.sslPort 属性指定 SSL 端口:

    shell
    ktor {
        deployment {
            sslPort = 8443
        }
    }
    yaml
    ktor:
        deployment:
            sslPort: 8443
  2. 在单独的 security 组中提供密钥库设置:

    shell
    ktor {
        security {
            ssl {
                keyStore = keystore.jks
                keyAlias = sampleAlias
                keyStorePassword = foobar
                privateKeyPassword = foobar
            }
        }
    }
    yaml
    ktor:
        security:
            ssl:
                keyStore: keystore.jks
                keyAlias: sampleAlias
                keyStorePassword: foobar
                privateKeyPassword: foobar

有关完整示例,请参见 ssl-engine-main

embeddedServer

如果你使用 embeddedServer 函数来运行服务器,你需要在 ApplicationEngine.Configuration 中配置一个 自定义环境,并使用 sslConnector 在其中提供 SSL 设置:

kotlin
import io.ktor.network.tls.certificates.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.slf4j.*
import java.io.*
import java.security.KeyStore

fun main() {
    embeddedServer(Netty, applicationEnvironment { log = LoggerFactory.getLogger("ktor.application") }, {
        envConfig()
    }, module = Application::module).start(wait = true)
}

private fun ApplicationEngine.Configuration.envConfig() {

    val keyStoreFile = File("build/keystore.jks")
    val keyStore = buildKeyStore {
        certificate("sampleAlias") {
            password = "foobar"
            domains = listOf("127.0.0.1", "0.0.0.0", "localhost")
        }
    }
    keyStore.saveToFile(keyStoreFile, "123456")

    connector {
        port = 8080
    }
    sslConnector(
        keyStore = keyStore,
        keyAlias = "sampleAlias",
        keyStorePassword = { "123456".toCharArray() },
        privateKeyPassword = { "foobar".toCharArray() }) {
        port = 8443
        keyStorePath = keyStoreFile
    }
}

有关完整示例,请参见 ssl-embedded-server