【问题标题】:secure HTTP communication for components of commercial product商业产品组件的安全 HTTP 通信
【发布时间】:2015-09-10 14:44:16
【问题描述】:

假设我想发布一个商业产品,它有两个组件,用 Java 编写,使用 RESTful API 在本地网络上相互通信。它可以是音乐管理器、联系人数据库、食谱 --- 重要的是这是一个合理且极有可能的场景。

请注意,我说的是通过本地网络相互通信的两个组件——而不是与我的服务器通信。

那么如何确保通信安全?

我知道如果我为全世界设置一个 HTTP 服务器,我可以(甚至便宜地)购买 SSL 证书。我已经做到了。但是我不能告诉用户去购买证书——他们不知道我在说什么,也永远不知道如何安装它。

那我该怎么办?向每个人发送我自己的自签名证书并做一件非常糟糕的事情,比如disable certificate validation in Java?可怕,我知道。但至少信息不会以纯文本形式出现。

谁有更好的解决方案?

【问题讨论】:

  • 您的链接答案提供了另一种解决方案:不是禁用自签名证书的证书验证,而是“导出证书 (...) 并将其导入您的 JVM 信任库”
  • 您想完全隐藏请求的内容还是只是确保它们不是来自任何地方并被接受?
  • 我想尽可能地保护通信,但主要是我不希望通信以明文形式通过网络(我并不是说我只想混淆它)。

标签: java rest ssl ssl-certificate


【解决方案1】:

2015 年 9 月 20 日更新 阐明 cmets 中提出的观点

要了解如何做到这一点,让我们检查一下此类应用程序的可能部署场景。假设所讨论的应用程序包含两个组件 - 客户端部分和服务器部分,旨在安装到本地网络上的不同计算机上。我们希望我们的服务器部分只接受安全连接,因此本地网络被认为是敌对的。

  1. 安装服务器部分。在安装时,使用目标计算机的主机名以编程方式创建自签名证书。如果计算机没有 DNS 记录(如 myserver.mycorp.com),请使用其 IP 地址 - 它必须是静态的,因为我们需要将客户端部分指向它。您可以使用Bouncy Castle API 在代码中创建证书。

  2. 将客户端部分安装到另一台计算机上,并将生成的证书复制到安装文件夹中。手动执行此操作有效地在服务器和客户端之间建立信任。尝试通过敌对网络上的未加密连接自动执行此操作将无法达到目的。

  3. 由于您严格保护自己的应用程序部分之间的通信,因此您可以完全控制相关应用程序信任哪些证书。在客户端上,创建一个密钥库,并将生成的证书添加到其中:

    FileInputStream fis = new FileInputStream(yourCertificateFile);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    X509Certificate c = (X509Certificate)cf.generateCertificate(fis);
    
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null, aRandomKeystorePasswordCharArray);
    ks.setCertificateEntry(aUniqueNameForYourCertificate, c);
    
    FileOutputStream fos = new FileOutputStream(aRandomKeystoreFileName);
    ks.store(fos, aRandomKeystorePasswordCharArray);
    fos.close();
    

    告诉 JVM,您的应用程序只会信任来自其自己的密钥库的证书。

    // replace backslashes '\' with slashes '/' in aRandomKeystoreFileName on Windows
    System.setProperty("javax.net.ssl.trustStore", aRandomKeystoreFileName);
    System.setProperty("javax.net.ssl.trustStorePassword", aRandomKeystorePassword);
    

【讨论】:

  • Roman,如果以编程方式启用密钥库就像在运行时设置密钥库属性一样简单,我是否可以简单地为每个组件提供在 JAR 文件中预配置的密钥库?还是我必须将其复制到裸文件路径?动态创建密钥库有什么好处/需要?
  • Omikron 是正确的。如果你想使用javax.net.ssl.trustStore,你必须有一个单独的密钥库文件。但是,您可以使用在运行时创建的密钥库(驻留在内存中)来创建自定义 SSL 上下文。您甚至可以将这样的上下文设置为应用程序使用的默认上下文。另外,我还更新了提到javax.net.ssl.trustStorePassword的答案。
  • 如果我想为其中一个组件提供 Web 界面,那么所有的赌注都没有了吗?每个浏览器都会告诉我连接不安全。它甚至没有正确的主机名。 :(
  • 或多或少。所有的浏览器都会抱怨。但是,如果您知道运行组件的机器的 IP 地址,并且可以使用自签名证书,并且您愿意加倍努力 - 您可以生成 SSL 证书即时获取该 IP。这样主机名就OK了。
【解决方案2】:

使用 OAuth 2.0 来保护您的服务,您应该只向您的客户端提供令牌,而不是双向 SSL。 Facebook、Google 等使用它。

https://en.wikipedia.org/wiki/OAuth

【讨论】:

  • 我很好奇这有什么帮助? OP 对加密很感兴趣,在那个链接中它说“OAuth 2.0 不支持签名、加密、通道绑定或客户端验证。它完全依赖 SSL 来实现某种程度的机密性和服务器身份验证。”这似乎没有为安全通信提供解决方案。
  • OP 对确保其服务与客户之间的互动安全感兴趣。除了使用 2 路 SSL 之外,应该可以使用带有 OAuth 协议的单路 SSL,它提供了通过令牌而不是证书来验证用户的能力。它不是一种传输安全技术,它是一种基于请求的安全技术。我只是提供了一个替代方案。
【解决方案3】:

您的linked answer 提出了另一种解决方案:不要禁用自签名证书的证书验证,而是“导出证书 (...) 并将其导入您的 JVM 信任库”。

所以只有在第一次发现未知证书时,要求用户确认。

【讨论】:

  • 我正在向 Joe/Jane 用户运送一个商业产品。我真的希望他或她打开命令提示符并将证书导入 JVM 信任库吗?他/她不知道什么是证书或信任库。他知道他/她在安装浏览器或媒体播放器或其他任何打算供普通人使用的东西时不必搞砸这个。我不明白这是一个现实的选择。如果我的目标市场是程序员,那我一开始就没有问题……
  • ...因为我在您提供的链接中阅读答案的方式是导入到 JVM 信任库是从命令提示符手动操作的。我可以在 Java 程序中以编程方式执行此操作吗?如果不是,那么我认为这不是一个可行的解决方案。
【解决方案4】:

在TheNextWeb查看 Facebook Connect、OAuth 和 OpenID 之间的比较

OpenID:OpenID 作为第三方可以验证您的身份

OAuth:人们向您授予访问权限的更安全的方式

Facebook Connect:通过 Facebook Connect,我们看到的是 OpenID 和 OAuth 的元素。 Facebook Connect 可以验证您的真实身份,然后在您获得许可后,它可以提供对您数据的访问权限。

总结:

OpenID 和 OAuth 认为他们有一个集体的正确答案,但 Facebook 显然认为它有自己的。我们必须看看它在未来会如何形成。

【讨论】:

猜你喜欢
  • 2013-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 2021-12-12
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
相关资源
最近更新 更多