FtpServer
  1. FtpServer
  2. FTPSERVER-277

Ftplet which forces TLS/SSL for control and data channels when using explicit FTPS

    Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 1.1.0
    • Component/s: Ftplets
    • Labels:
      None

      Description

      I've developed a simple Ftplet which forces the client to use secure control and data channels when the server has been configured for explicit FTPS. The code has been pasted below. Let me know what you think about it. I've tried it with curl and it seems to work as expected both for passive and active data channels. Feel free to include it in Ftpserver if you find it useful.

      import java.io.IOException;
      import java.util.HashSet;
      import java.util.Set;

      import org.apache.ftpserver.ftplet.DefaultFtpReply;
      import org.apache.ftpserver.ftplet.FtpException;
      import org.apache.ftpserver.ftplet.FtpReply;
      import org.apache.ftpserver.ftplet.FtpRequest;
      import org.apache.ftpserver.ftplet.FtpSession;
      import org.apache.ftpserver.ftplet.Ftplet;
      import org.apache.ftpserver.ftplet.FtpletContext;
      import org.apache.ftpserver.ftplet.FtpletResult;

      /**

      • {@link Ftplet} which forces the client to use secure control and data
        * channels when connecting in explicit FTPS mode. In implicit FTPS the control
        * channel is always secure, however, the data channel can be plain text. This
        * {@link Ftplet}

        will not allow clients to open insecure data channels in

      • implicit FTPS mode.
        *
      • @version $Id$
        */
        public class ExplicitSslForcingFtplet implements Ftplet {
        private static final String SECURE = ExplicitSslForcingFtplet.class.getName() + ".secure";
        private static final Set<String> DATA_CHANNEL_COMMANDS;

      static

      { DATA_CHANNEL_COMMANDS = new HashSet<String>(); DATA_CHANNEL_COMMANDS.add("APPE"); DATA_CHANNEL_COMMANDS.add("LIST"); DATA_CHANNEL_COMMANDS.add("MLSD"); DATA_CHANNEL_COMMANDS.add("NLST"); DATA_CHANNEL_COMMANDS.add("RETR"); DATA_CHANNEL_COMMANDS.add("STOR"); DATA_CHANNEL_COMMANDS.add("STOU"); }

      public FtpletResult afterCommand(FtpSession session, FtpRequest request,
      FtpReply reply) throws FtpException, IOException {

      String cmd = request.getCommand().toUpperCase();
      int code = reply.getCode();
      if ("AUTH".equals(cmd) && code >= 200 && code < 300)

      { session.setAttribute(SECURE, true); }

      return FtpletResult.DEFAULT;
      }

      public FtpletResult beforeCommand(FtpSession session, FtpRequest request)
      throws FtpException, IOException {

      String cmd = request.getCommand().toUpperCase();
      boolean secure = (Boolean) session.getAttribute(SECURE);
      if ("USER".equals(cmd)) {
      if (!secure)

      { session.write(new DefaultFtpReply(500, "Control channel not secure. Issue AUTH command first.")); return FtpletResult.SKIP; }

      } else if (DATA_CHANNEL_COMMANDS.contains(cmd)) {
      if (!session.getDataConnection().isSecure())

      { session.write(new DefaultFtpReply(500, "Data channel not secure. Issue PROT command first.")); return FtpletResult.SKIP; }

      }

      return FtpletResult.DEFAULT;
      }

      public void destroy() {
      }

      public void init(FtpletContext ftpletContext) throws FtpException {
      }

      public FtpletResult onConnect(FtpSession session) throws FtpException,
      IOException

      { session.setAttribute(SECURE, session.isSecure()); return FtpletResult.DEFAULT; }

      public FtpletResult onDisconnect(FtpSession session) throws FtpException,
      IOException

      { return FtpletResult.DEFAULT; }

      }

        Activity

        Hide
        Niklas Gustavsson added a comment -

        I will have a look at providing something similar, but probably more integrated than an Ftplet for 1.1.

        Show
        Niklas Gustavsson added a comment - I will have a look at providing something similar, but probably more integrated than an Ftplet for 1.1.
        Hide
        Bob Ziuchkovski added a comment -

        I would like to request support for this as well, but as Niklas mentioned, in a more integrated fashion. Ideally it would be nice to have the following properties:

        <nio-listener force-ssl="true">
        <data-connection force-ssl="true">

        If either of these has 'implicit-ssl="true"' set, then the force-ssl option essentially becomes a no-op. Otherwise, SSL is forced before sensitive data can be sent. When force-ssl is enabled on a control channel, respond something like '530 Access denied.' or '534 Insufficient data protection.' to all commands except for 'STARTTLS' (and perhaps FEAT?) from the client until the TLS connection is established. 'CCC' command would be rejected. If force-ssl is enabled for the data channel, the client must send 'PROT P' prior to sending commands that would open a data channel connection. If the
        client sends such commands before a 'PROT P', send back '534 Data protection required', and if the client sends a 'PROT C', respond '534 Insufficient data protection.'

        I'll admit that I'm not 100% confident on the above responses. They are based only on my reading of the relevant RFCs. However, something akin to this mechanism would wonderful. My experience has been that explicit mode SSL appears to be supported on a wider variety of FTP clients than implicit mode. I would like to deploy our FTP services in explicit mode, but don't wish to give people the ability to shoot themselves in the foot by sending sensitive data in cleartext.

        Show
        Bob Ziuchkovski added a comment - I would like to request support for this as well, but as Niklas mentioned, in a more integrated fashion. Ideally it would be nice to have the following properties: <nio-listener force-ssl="true"> <data-connection force-ssl="true"> If either of these has 'implicit-ssl="true"' set, then the force-ssl option essentially becomes a no-op. Otherwise, SSL is forced before sensitive data can be sent. When force-ssl is enabled on a control channel, respond something like '530 Access denied.' or '534 Insufficient data protection.' to all commands except for 'STARTTLS' (and perhaps FEAT?) from the client until the TLS connection is established. 'CCC' command would be rejected. If force-ssl is enabled for the data channel, the client must send 'PROT P' prior to sending commands that would open a data channel connection. If the client sends such commands before a 'PROT P', send back '534 Data protection required', and if the client sends a 'PROT C', respond '534 Insufficient data protection.' I'll admit that I'm not 100% confident on the above responses. They are based only on my reading of the relevant RFCs. However, something akin to this mechanism would wonderful. My experience has been that explicit mode SSL appears to be supported on a wider variety of FTP clients than implicit mode. I would like to deploy our FTP services in explicit mode, but don't wish to give people the ability to shoot themselves in the foot by sending sensitive data in cleartext.

          People

          • Assignee:
            Niklas Gustavsson
            Reporter:
            Niklas Therning
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development