Java ftps连接,TrustManager解释(使用filezilla服务器)

我已经编写了一个程序(显然是从网上COPIED,并根据我的需要进行了一些修改!),使用apache ftp api进行文件下载/上传,并使用Filezilla服务器创建本地服务器。 一切都很好 。 问题是我没有得到我们必须创建信任管理器的部分。

码:

FTPSClient ftpsClient= null; SSLContext sslContext = SSLContext.getInstance(protocol); TrustManager tm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { System.out.println("getAcceptedIssuers------"); return null; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub System.out.println("checkClientTrusted------"); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // TODO Auto-generated method stub System.out.println("checkServerTrusted------"); } }; sslContext.init(null, new TrustManager[] { tm }, null);//new SecureRandom()); ftpsClient = new FTPSClient(true, sslContext); 

public X509Certificate [] getAcceptedIssuers()根据文档,此方法返回受信任的对等身份validation的证书颁发者权限列表 。 但是在代码中,该方法返回null。

另外,在Filezilla Server中设置ftps配置时 ,我必须创建一个证书。

看到这一切,我没有得到证书创建的原因,因为我们没有通过或返回证书。 或者服务器或库是否在内部处理它。 有人可以解释我这个问题。

getAcceptedIssuers仅用于(Java)SSL / TLS服务器。 你显然是在“写”一个客户。

大多数情况下,SSL / TLS服务器需要证书和匹配的私钥 。 有些人将这些视为一件事,因为它们或多或少地在一起创造,但事实并非如此。 通常, 为每个服务器生成(创建)该对,但这并不总是必需或必需的; 我不知道特别是FileZilla服务器。 SSL / TLS中有一些选项可供服务器不使用证书(或“静态”预生成密钥)而不进行身份validation,但这些选项通常是禁用的(或完全未实现的),因为实际上这些连接经常被颠覆。 相反,客户端还可以选择使用证书+私钥进行身份validation,通常称为“双向”或“相互”身份validation,但很少使用它们。

回到通常情况,作为SSL / TLS“握手”的一部分,服务器提供一个证书,该证书标识由CA(或通常是多个CA的“链”)签名的服务器,客户端可以将其validation为可信,并使用握手协议中的私钥以两种方式之一。 在任何一种情况下,这certificate服务器到达的是正确的 – 或者更确切地说,提供的证据是为了说服CA正确的服务器具有该密钥(对),并且因此不知道密钥已被泄露。 有关详细信息,请参阅
https://security.stackexchange.com/questions/20803/how-does-ssl-work
https://security.stackexchange.com/questions/1779/how-does-an-ssl-server-prove-its-identity
https://security.stackexchange.com/questions/6737/what-is-an-ssl-certificate-intended-to-prove-and-how-does-it-do-it

您的“信任任何人”TrustManager绕过了与正确的服务器交谈的所有这些恼人的坚持。 它实际上说“我的数据是如此私密,它必须加密以防止人们窃取它,但我很高兴将它发送到由访问我的网络的小偷运行的虚假服务器,或其中的东西,或者我经常使用的DNS“。 如果您(并且将始终如此)在一个小的隔离网络上,这可能是安全的 – 或者至少欺诈性服务器的风险不大于您的客户端或服务器本身“被忽略”的风险,从而提供连接的安全性无意义的。 或者,如果数据实际上不是私有的,并且您只是使用SSL,因为服务器需要它(可能在这里不正确)或者您喜欢为自己做额外的工作,那么安全性并不重要。

编辑其他信息/问题:

好的,包含PEM格式“RSA PRIVATE KEY”和“CERTIFICATE”的文件正是我所说的服务器所需要的:证书和匹配的私钥。 (BEGIN xxx包围5个破折号的格式,base64数据,然后END xxx类似地很久以前为PEM定义,即使PEM本身已经放弃,仍然使用格式。)对这些内容使用后缀.crt是不寻常的有点混乱; FileZilla选择了那个还是你呢? 在任何情况下,客户只需要一个证书,不应该有私钥,所以你需要“提取”一些东西,但首先你需要看看你有什么。

你有什么? 除非FileZilla为您与CA进行交互,并且可能已经收到了您应该注意的付款,否则此证书几乎肯定是自签名的 ,即使用自己的密钥和名称进行签名,而不是由CA根据CA名称签名。 自签名证书通常不受广泛信任,需要管理更多工作,但如果此环境仅适用于您自己或像小型企业这样的有限群体,则自签名证书就足够了。 同样重要的是证书中的“主题”名称是什么:对于正确检查的SSL / TLS连接,证书中的名称必须与您请求连接的名称相匹配; 通常这是一个域名,但它可以是一个IP地址,您不需要域名的function(例如,您自己运行的服务器永远不会移动)。 还有其他选项可能不适用于此处。 要查看您拥有的内容,请将证书部分(从破折号-BEGIN CERTIFICATE行直至并包括dash-END行)复制到另一个文件,然后执行以下操作之一对其进行解码:

  • 在Windows名称上带有后缀.cer文件,然后双击它以显示详细信息,并查看Issued to:and Issued by:

  • 在安装了Java的系统上运行keytool -printcert -file /path/to/that/file并查看Owner:和Issuer:

  • 在具有OpenSSL的系统(Linux,其他人可能)上运行openssl x509 -in /that/file -noout -text并查看Subject:和Issuer:

你应该用什么? 如果您的发行者/由和主题/所有者/彼此相等并且与您的服务器名称相匹配,则您拥有良好的自签名证书。 还要检查有效日期(有效期,有效期或有效期之后)以确定它是否会很快过期 – 特别证书经常这样做。 此时,您有两个相互关联的选择。 首先,是否使用该证书或其他证书:

  • 如果您有一个良好的自签名证书(正确的服务器名称和有效性),您可以将它放在/每个客户端的信任存储区中使用它。

  • 如果没有,但你有(或得到)OpenSSL,你可以重新生成另一个自签名证书,它具有你需要的任何名称和有效性,并将它放在服务器 /每个客户端的信任库中。

  • 或者不是任何自签名证书,您可以从Java信任的已建立的CA(证书颁发机构)获得证书,例如Verisign,GoDaddy等。这通常每年花费一些钱或很少,并要求您certificate您的“权利”您希望在证书中使用的域名(通过各种方式,例如发送到您的MX的电子邮件,DNS中的数据,网络服务器上的数据等)此外,如今大多数CA都强制执行最佳做法,即您的RSA密钥必须为2048位(或更多) ,但你不需要更多); 我不知道FileZilla是否足以生成大小的密钥,如果没有,您必须先生成一个新密钥(使用openssl),然后才能继续从CA获取证书。 CA方法的优点是不需要添加到/每个客户端的信任存储区。

怎么信任呢? 在客户端,如上所述,您不需要为真正的CA方法做任何事情。 但对于自签名方法,使用包含FTPS客户端的Java SSL客户端,该自签名证书必须位于客户端使用的信任库中,并且此处有以下几种方法:

  • 使用JRE默认信任库,如果文件存在,则为文件jssecacerts ,否则文件cacertsJREHOME/lib/security即在安装JRE的任何位置下的子目录lib/security 。 您正在使用的FTPSClient可能有一种方法可以使用使用默认信任库的JRE默认SSLContext ,或者您可以将其传递给SSLContext.getDefault() 。 如果这是您需要SSL连接的唯一主机,只需将您的something.cer PEM文件从上面放入jssecacerts,
    keytool -importcert -keystore jssecacerts -file /path/to/something.cer和password changeit (输入两次)。 如果您需要来自同一JVM或JRE的其他SSL连接,尤其是公共Internet,首先将cacerts复制到jssecacerts,并在-importcert上指定-alias myfilezilla (或唯一的变体,仅限字母和数字)。

  • 覆盖默认的信任库。 通过keytool -importcert -keystore /path/to/mytrust -file /path/to/something.cer创建一个包含(仅)您的证书的密钥库,并将/ path / to / mytrust放入客户端或与客户端或某个地方您(以及任何其他用户)将很容易记住与您的客户相关联。 然后将系统属性javax.net.ssl.trustStore设置为JVM中的该文件。 有几种方法可以做到这一点:在命令行中始终使用-D或在代码中调用System.setProperty(n,v) (在第一次创建SSL套接字之前); 在某些应用程序环境中,还有其他系统属性配置或管理function。

  • 编码自己的信任库。 创建一个java.security.KeyStore并使用包含您的证书的数据加载它 – 直接(通过CertificateFactory.setCertificateEntry读取证书)或加载您之前使用keytool创建的文件,如上所述; 然后用你的密钥库创建一个真实的(没有唠叨的) javax.net.ssl.TrustManager.init它; 然后以与现在相同的方式在SSLContext中使用TrustManager 。 这更复杂,如果上面的任何一个更简单的选项适合您,我不推荐它。