无法握手具有端口 587 和 server="smtp.gmail.com" 的 ssl 套接字
Posted
技术标签:
【中文标题】无法握手具有端口 587 和 server="smtp.gmail.com" 的 ssl 套接字【英文标题】:Cannot handshake ssl sockets having port 587 and server="smtp.gmail.com" 【发布时间】:2018-06-27 10:24:21 【问题描述】:此代码适用于 PORT=465。 但是对于 PORT=587,它会抛出异常 "Exception in thread main javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?"
package smtpClient;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import javax.naming.NamingException;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
class TLS_Mime_G
static final int PORT = 587;
static String REMOTEHOST = "smtp.gmail.com";
public static void main(String[] args)
throws IOException, NoSuchAlgorithmException, NamingException, KeyManagementException
SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) ssf.createSocket(REMOTEHOST, PORT);
socket.setEnabledProtocols(socket.getSupportedProtocols());
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
socket.addHandshakeCompletedListener(new MyTLSHandshakeListener());
socket.startHandshake();//Throws Error
System.out.println("Connected to " + socket.getRemoteSocketAddress());
class MyTLSHandshakeListener implements HandshakeCompletedListener
public void handshakeCompleted(HandshakeCompletedEvent e)
System.out.println("Handshake succesful!");
System.out.println("Cipher suite used: " + e.getCipherSuite());
/* 支持的协议:SSLv2Hello 支持的协议:SSLv3 支持的协议:TLSv1 支持的协议:TLSv1.1 支持的协议:TLSv1.2 启用的协议:TLSv1 启用的协议:TLSv1.1 启用的协议:TLSv1.2 */
【问题讨论】:
会不会是因为其中一个端口是 SSL (465) 而另一个是 TLS(587) 而 ypur 库不支持 TLS?也许需要不同的设置... 没有。我确实检查了支持和启用的协议 支持TLS 【参考方案1】:465 是“隐式”TLS-以前的 SSL;您在 TCP 级别进行连接,然后立即并始终启动 TLS 连接,并且(如果成功)然后通过 TLS(通过 TCP)连接执行 SMTP。
587 是“显式”TLS-以前的 SSL;您在 TCP 级别连接并通过读取服务器公告并至少执行 EHLO 命令和响应(可能/可选其他)开始执行 SMTP,然后执行 STARTTLS 命令并检查响应,如果成功则开始 TLS 连接现有的 TCP 连接,然后(如果成功)然后通过 TLS over TCP 连接执行 SMTP。 Have a look at rfc 3207.
你的例外已经告诉你了;它表示您连接到的服务器(尚未)执行 SSL/TLS,而是执行明文——在本例中为明文 SMTP。
此外,启用所有受支持的版本和密码套件是一个非常糟糕的主意;他们中的许多人在默认情况下被禁用因为他们不安全。虽然 SSLv3 在这种特殊情况下被 POODLE(!) 破坏了,但没关系,因为 gmail(非常正确)永远不会协商它; OTOH 启用 ECDH_anon_AES* 等匿名套件允许主动攻击者轻松拦截、读取和/或更改您所谓的安全电子邮件。
或者只使用 javamail,它已经正确地实现了所有这些选项以及更多选项。
【讨论】:
我明白 STARTTLS 在端口:587 上未激活。但是我应该如何给出 STARTTLS 命令?当我在 SSLSocket 输出流中给出 EHLO 命令时,我得到了同样的异常......那么我如何让服务器做 SSL/TLS 而不是做明文? (而且我不允许使用 javamail) @Shashank STARTTLS 在 587 上用于某些服务器,包括这台服务器;不使用的是自动 SSL/TLS。正如我所说,打开一个 TCP(明文)连接——即java.net.Socket
——而不是一个 TLS 连接。通过 TCP 连接执行 EHLO 和 STARTTLS。在检查响应指示成功后,然后使用 docs.oracle.com/javase/8/docs/api/javax/net/ssl/… 中记录的 createSocket 重载通过现有 TCP 连接启动 TLS 连接以上是关于无法握手具有端口 587 和 server="smtp.gmail.com" 的 ssl 套接字的主要内容,如果未能解决你的问题,请参考以下文章
C# SMTP 无法在 Outlook.com 端口 587 上进行身份验证。“服务器响应为:5.7.1 客户端未通过身份验证”
查看端口 587、25、110、465、995、143、993 上的 SSL 证书
CDO 在端口 465 和 587 上连接失败,但在 25 上工作