java - FTP协议(protocol)如何协商SSL连接?

标签 java sockets ssl ftp network-programming

<分区>


想改进这个问题吗? 通过 editing this post 添加细节并澄清问题.

关闭 7 年前

我已阅读 RFC 并尝试在我的 FTP 服务器中实现 SSL 连接。

我已经使用 javax.net.ssl.SSLSocket 将我所有的套接字切换到 SSLServer 套接字和 SSLsockets; javax.net.ssl.SSLSocketFactory;

当使用 FileZilla 使用 SSL 显式加密时,我收到一条消息说, “连接到 127.0.0.1,协商 SSL 连接”

它会卡在那里。

如何对我的服务器进行编程以协商 SSL 连接?

下面这段代码是启动 ServerSocket 并等待连接的地方。

// Starts a server Socket to listen to new clients
        System.setProperty("javax.net.ssl.trustStore","ServerFiles\\default_KeyStore\\server.keystore");
        SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
        this.entryPortSock = (SSLServerSocket)sslserversocketfactory.createServerSocket((Integer) st.getValue("CMDPort"));
        SSLSocket scCMDPort;

        // Initiates the Rolling Log
        RollingLog rollingLog = new RollingLog((String) st.getValue("LOGfiledirectory"), st);
        Runnable RunnableRollingLog = rollingLog;
        Thread logger = new Thread(RunnableRollingLog);
        logger.start();

        // Continues to listen to new clients and connect to them when
        // available.
        while (true) {
            scCMDPort =(SSLSocket) this.entryPortSock.accept();
            System.out.println("System accepted a new friend!");

            // Starting the service for the client
            Runnable ftpService = new FTPService(rollingLog, (String) st.getValue("ROOT"), scCMDPort, st);
            Thread service = new Thread(ftpService);
            service.start();
        }

下面是我的服务器可以从客户端接受的支持的命令。

 private void action(ServerCmd command) {
    // Process of logging in, Must pass this boundary before any other
    // command can be given.

    if (DEBUG_INCOMING) {
        System.out.println("Client: " + command.cmdType + " " + reJoinString(command.args));
    }
    printLog("Client: " + command.cmdType + " " + reJoinString(command.args));

    if (command.cmdType.equals(ServerCommands.AUTH)) {
        if(command.args.get(0).equalsIgnoreCase("SSL")){


            this.sendOut("334 Yo homie we can start that SSL connection!");
        }
    }
    else if (command.cmdType.equals(ServerCommands.USER)) {
        this.User(command);
    }

    else if (command.cmdType.equals(ServerCommands.PASS)) {
        this.Pass(command.args.get(0));
    }

    // After login in, all of these commands can be read.
    else if (this.Status == 1) {
        if (command.cmdType.equals(ServerCommands.SYST)) {
            // Reads a request for the operating system of the Server.
            this.Syst();
        }

        else if (command.cmdType.equals(ServerCommands.FEAT)) {
            // Reads a request FEAT
            this.Feat();
        } else if (command.cmdType.equals(ServerCommands.PWD)) {
            // Reads a request to print the working directory
            this.Pwd();
        }

        else if (command.cmdType.equals(ServerCommands.TYPE)) {
            // Read a request Type
            this.Type(command.args.get(0));
        }

        else if (command.cmdType.equals(ServerCommands.PASV)) {
            // Request PASV connection
            this.Pasv();
        } else if (command.cmdType.equals(ServerCommands.LIST)) {
            // Request directory listing
            this.List();
        }

        else if (command.cmdType.equals(ServerCommands.CWD)) {
            //
            String temp = this.reJoinString((command.args));
            this.Cwd(temp);
        }

        else if (command.cmdType.equals(ServerCommands.CDUP)) {
            this.Cdup();
        }

        else if (command.cmdType.equals(ServerCommands.STOR)) {
            this.Stor(this.reJoinString(command.args));
        } else if (command.cmdType.equals(ServerCommands.RETR)) {
            this.Retr(this.reJoinString(command.args));
        } else if (command.cmdType.equals(ServerCommands.QUIT)) {
            System.exit(0);
        } else if (command.cmdType.equals(ServerCommands.HELP)) {
            sendOut("214 Help: Connect to FileZilla, the older version without caching to use this FTP Server. Or, a command prompt client would work as well.\n"
                    + "Accepted FTP Commands: USER, PASS, SYST, FEAT, PWD, TYPE, PASV, LIST, CWD, CDUP, EPSV, STOR, RETR, QUIT");
        } else if (command.cmdType.equals((ServerCommands.PORT))) {
            if (((String) (this.settings.getValue("PORTmode"))).equalsIgnoreCase("YES")) {
                this.Port(this.reJoinString(command.args));
            } else {
                sendOut("522 This command is not supported");
            }
        } else if (command.cmdType.equals(ServerCommands.EPRT)) {
            if (((String) (this.settings.getValue("PORTmode"))).equalsIgnoreCase("YES")) {
                this.EPRT(this.reJoinString(command.args));
            } else {
                sendOut("522 This command is not supported");
            }
        } else if (command.cmdType.equals((ServerCommands.EPSV))) {
            // Turn true to support EPSV
            if (((String) (this.settings.getValue("PASVmode"))).equalsIgnoreCase("YES")) {
                this.EPSV();
            } else {
                sendOut("522 This command is not supported");
            }
        }
    }

更新: 一旦从客户端发送了 AUTH SSL 命令,我就实现了从套接字到 SSL 套接字的升级。这是我的代码:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
            this.clientSocket1 = sslsocketfactory.createSocket(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
            ((SSLSocket)this.clientSocket1).setUseClientMode(false);
            this.sendOut("334 Yo homie we can start that SSL connection!");

客户端响应: Client: €j Q [] 9 8 5 [] [] 类似的东西。如何解密消息?

为了尝试解决上述问题,我使用以下代码重新实例化了我的缓冲区读取器,该读取器从常规套接字读取到来自 SSLSocket 的流:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
            this.clientSocket1 = sslsocketfactory.createSocket(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
            ((SSLSocket)this.clientSocket1).setUseClientMode(false);
            ((SSLSocket)this.clientSocket1).startHandshake();
            cipher  =sslsocketfactory.getDefaultCipherSuites();
            this.encrypted = true;
            this.sendOut("334 Yo homie we can start that SSL connection!");
            this.in = new BufferedReader(new InputStreamReader(((SSLSocket)this.clientSocket1).getInputStream()));
            this.out = new PrintWriter(((SSLSocket)this.clientSocket1).getOutputStream());

可能的握手崩溃的整个堆栈跟踪。

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at FTPServer.FTPService.run(FTPService.java:100)
at java.lang.Thread.run(Unknown Source)

客户端的日志:<--- 文件 zilla 响应:220 IiiiDeentiffy YouuurSelf!!! 命令:AUTH SSL Response: 234 Yo homie 我们可以启动 SSL 连接了!

服务器的日志<--- 我正在编程的那个

javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
at sun.security.ssl.SSLSocketImpl.checkEOF(Unknown Source)
at sun.security.ssl.AppInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at FTPServer.FTPService.run(FTPService.java:100)
at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext     connection?
at sun.security.ssl.InputRecord.handleUnknownRecord(Unknown Source)
at sun.security.ssl.InputRecord.read(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.getSession(Unknown Source)
at FTPServer.FTPService.action(FTPService.java:143)
at FTPServer.FTPService.run(FTPService.java:102)
... 1 more

服务线程已停止?!

较短的版本

package testServer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class driverServerTest {
public static void main(String args[]) {
    try {
        ServerSocket Ssc = new ServerSocket(21);
        Socket sc;
        sc = Ssc.accept();
        PrintWriter out = new PrintWriter(sc.getOutputStream());
        BufferedReader in = new BufferedReader(new InputStreamReader(sc.getInputStream()));
        out.println("220 The connection succeeded");
        out.flush();
        String temp;
        while (true) {
            temp = in.readLine();
            System.out.println(temp);
            if (temp.equalsIgnoreCase("AUTH SSL")) {
                out.println("334 Yo homie we can start that SSL connection!");
                out.flush();
                SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
                sc = sslsocketfactory.createSocket(Ssc.getInetAddress().getHostAddress(), Ssc.getLocalPort());
                ((SSLSocket) sc).setUseClientMode(false);

                in = new BufferedReader(new InputStreamReader(((SSLSocket) sc).getInputStream()));
                out = new PrintWriter(((SSLSocket) sc).getOutputStream());
                out.println("234 request login information");
                out.flush();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

客户回复:

Status: Connecting to 127.0.0.1 ...
Status: Connected with 127.0.0.1, negotiating SSL connection...
Response:   220 The connection succeeded
Command:    AUTH SSL
Response:   334 Yo homie we can start that SSL connection!

最佳答案

您需要从普通的 ServerSocket 开始,然后使用 SSLSocketFactory.createSocket(Socket, ...) 将普通的 Socket 升级为如果您收到 AUTH TLS 命令,则使用 SSL。

在使用它执行任何 I/O 之前,不要忘记调用 SSLSocket.setUseClientMode(false);

关于java - FTP协议(protocol)如何协商SSL连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33729974/

上一篇:ssl - 您可以通过 .ebextensions 文件配置 Elastic Beanstalk Load Balancer SSL 证书吗?

下一篇:ssl - Rails Devise Omiauth 回调返回 domain.com :443 instead of https://domain. com

相关文章:

java - cucumber 测试失败后Maven构建成功

Java - 查找仅在测试中使用的方法(在源代码中未使用)

c - 在客户端套接字程序中使用 select()

connect() 到外部 IP 不工作

security - 为什么客户端和服务器要有相同的证书链

Java Web 服务检查 SSL 握手警报 : handshake_failure

c# - SslStream AuthenticateAsServer 无法识别提供给包的凭据

java - Go JNI异常0xc0000005信号在外部代码执行期间到达

java - 如何在 Apache POI 单元格中设置最小宽度?

javascript - 为什么我的代码会断开 Node 中的 Socket.io 连接?