【问题标题】:Easy secure connection over unsafe network (both endpoints fully controlled)通过不安全的网络轻松安全连接(两个端点完全受控)
【发布时间】:2012-09-02 20:37:15
【问题描述】:

我需要通过不受信任的网络连接客户端和服务器。我考虑过使用TLS (crypto/tls),但据我了解,我首先需要创建一个crypto/x509.Certificate。但我对需要传递给x509.CreateCertificate() function 的所有参数感到不知所措——它说它需要以下所有字段:

序列号、主题、NotBefore、NotAfter、KeyUsage、BasicConstraintsValid、IsCA、MaxPathLen、SubjectKeyId、DNSNames、PermittedDNSDomainsCritical、PermittedDNSDomains。

我可以完全控制两个端点,所以我相信我不需要任何过期或失效支持/参数(我可以随时更改客户端和服务器上的密钥) - 所以我可以跳过 NotBeforeNotAfter (?还是我必须设置它们?)。我应该在所有其他字段中添加什么内容,为什么要避免任何漏洞?另外,我可以使用相同的私钥/公钥对进行两种身份验证(客户端到服务器,服务器到客户端),还是必须使用 2 对?

或者,我可以使用比 TLS 更简单的东西吗?但是请注意,我需要进行两种身份验证。

编辑:

我根据接受的答案的建议创建了一个简单的库,以及来自generate_cert.go 的密钥生成代码 - 请参阅:

github.com/akavel/tunnel

【问题讨论】:

    标签: security authentication encryption network-programming go


    【解决方案1】:

    Owlstead 部分正确。您最好的选择是使用 OpenSSL 创建自签名证书。但是,我会使用 Go TLS 库进行加密。以下是一些可能对您有所帮助的代码。

    创建 x509 密钥对

    我通常按照here 的说明进行操作。命令摘要(对客户端和服务器都执行):

    openssl genrsa -des3 -out server.key 1024
    openssl req -new -key server.key -out server.csr
    cp server.key server.key.org
    openssl rsa -in server.key.org -out server.key
    openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
    

    使用 Go 的 TLS 库

    首先,创建一个tls.Config。一个 TLS 配置适用于客户端和服务器,但一些选项只需要在其中一个上设置:

    cert, err := tls.LoadX509KeyPair(cert, key)
    config := &tls.Config{
        Certificates: []Certificates{cert},
        ClientAuth: tls.RequireAnyClientCert, // Must be done on server
        InsecureSkipVerify: true, // Must be done on client
    }
    

    在服务器上,您需要设置一个 TLS 监听器。这会将其设置在端口 4443 上:

    listener, err := tls.Listen("tcp", ":4443", config)
    for {
        conn, err := listener.Accept()
        acceptConn(conn) // your code
    }
    

    在客户端:

    conn, err := tls.Dial("tcp", serverAddr, config)
    

    这将创建一个加密连接,但它不会验证对方是他们所说的身份。最简单的方法是为每台服务器提供另一台服务器的公钥,并将其与刚刚连接的服务器进行比较。要在另一台服务器上查找公钥,您需要:

    c := conn.(*tls.Conn) // convert net.Conn from listener to tls conn
    err := c.Handshake() // ensure handshake is completed without error
    state := c.ConnectionState()
    pubKey, err := x509.MarshalPKIXPublicKey(state.PeerCertificates[0])
    bytes.Equal(pubKey, knownKey) // compare to known value
    

    【讨论】:

    • 你写了“给每个服务器另一个服务器的公钥” - 那么,我应该使用一对密钥还是两个?从答案中我不清楚。还有,为什么不使用 Go 的密钥生成功能,而是使用 OpenSSL?
    • 我会使用两对钥匙。至于为什么要避免使用 Go 的密钥生成功能……我没有理由。使用 openssl 更容易。
    • 但是在Config 中,我必须在服务器和客户端上使用同一对,不是吗?那么第二对放在哪里呢?
    • 不,您应该为每个使用不同的密钥对。
    • @akavel 对于普通的 TLS 实现,公用名 (CN) 应包含主机名。因此,如果仅针对不同的主机名,您将需要两个证书。使用相同的密钥对创建两个证书可能比仅创建两个自签名证书更难。
    【解决方案2】:

    正如 owlstead 所说,TLS 仍然是您的最佳选择。可以按照一些在线指南创建自己的证书。

    以下文章可让您创建自己的 SSL 根证书(您实际上成为自己的根 CA,如 Verisign 等)。有了这个,您可以创建和签署您自己的应用程序证书并分发它们。如果如您所说,您可以完全控制两个端点,那么这可能值得一试。

    http://www.eclectica.ca/howto/ssl-cert-howto.php/

    【讨论】:

      猜你喜欢
      • 2018-11-24
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      相关资源
      最近更新 更多