Join the social network of Tech Nerds, increase skill rank, get work, manage projects...
 
  • Help with java defensive programming technique

    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 0
    • 609
    Answer it

    I have a the following four classes.. 

    FTPApplication- Models FTP commands in a modular, extendible way. This abstract class provides
    several methods used by both the client and server.
    ServerSession- Models an FTP session with a client. Implements methods declared by FTPApplication
    from the perspective of an FTP server.
    FTPServer- A pseudo FTP server. Accepts client connection and initiates a session.
    FTPClient- A pseudo-FTP client. Connects to server and enters a control loop which enables it to
    query the server.

    I want to make appropriate changes to harden the software system against attack and misuse. How can I do that and what changes do I need to make?


    This code is working correctly but I want to make it more secure and harden it for misuse. 

    import java.io.*;
    import java.net.Socket;
    import java.text.MessageFormat;
    import java.util.StringTokenizer;
    
    /**
     * Models FTP commands in a modular, extendible way. This abstract class
     * provides several methods used by both the client and server.
     * 
    
    abstract public class FTPApplication {
        /* constants common to the client and server */
        static final int SOCKET_TIMEOUT = 300000;
        static final int ERROR = -1;
        static final String DEFAULT_FILEBASE = "user.dir";
    
        /* FTP commands */
        static final String PUT = "put";
        static final String GET = "get";
        static final String LS = "ls";
        static final String EXIT = "exit";
    
        /* Path to the directory from which to serve or store files */
        protected String fileBase;
    
        /* Network I/O objects used for sending/receiving data */
        protected Socket socket;
        protected BufferedReader lineIn;
        protected PrintWriter lineOut;
    
        /* Flag used to break session loop */
        protected boolean exitRecieved = false;
    
        // ----------------------------------------------------------------------
        // CONSTRUCTOR
        // ----------------------------------------------------------------------
    
        /**
         * Default constructor. Establishes file base.
         * 
         * @param filebase
         *            The directory from which to read & write files.
         */
        public FTPApplication(String filebase) {
            try {
                File path = new File(filebase);
                this.fileBase = path.getCanonicalPath() + File.separator;
            } catch (IOException ioe) {
                this.fileBase = "";
                System.err.printf("Could not access %s: %s", filebase, ioe);
            }
        }
    
        // ----------------------------------------------------------------------
        // PROTECTED METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Sets a timeout on the socket and instantiates I/O objects.
         * 
         * @throws IOException
         */
        protected void setUpIO() throws IOException {
            if (socket != null) {
                socket.setSoTimeout(SOCKET_TIMEOUT);
                InputStreamReader input = new InputStreamReader(
                        socket.getInputStream());
                lineIn = new BufferedReader(input);
                lineOut = new PrintWriter(socket.getOutputStream(), true);
            } else {
                System.err.println("Cannot set up IO, socket is null.\n");
            }
        }
    
        /**
         * Closes the socket and its associated I/O objects.
         */
        protected void terminate() {
            try {
                System.out.printf("Terminating session ... ");
                if (lineIn != null) {
                    lineIn.close();
                }
    
                if (lineOut != null) {
                    lineOut.flush();
                    lineOut.close();
                }
    
                if (socket != null) {
                    socket.close();
                }
    
                System.out.printf("done.\n");
    
            } catch (IOException ioe) {
                System.err.printf("I/O Error terminating session: %s\n", ioe);
            }
        }
    
        /**
         * Calls the proper method based on user input.
         * 
         * @param args
         *            User arguments
         */
        protected void processCommand(StringTokenizer args) {
            if (args.hasMoreTokens()) {
                String command = args.nextToken();
                if (command.equalsIgnoreCase(PUT)) {
                    String file = args.hasMoreTokens() ? args.nextToken() : null;
                    handlePut(file);
                } else if (command.equalsIgnoreCase(GET)) {
                    String file = args.hasMoreTokens() ? args.nextToken() : null;
                    handleGet(file);
                } else if (command.equalsIgnoreCase(LS)) {
                    handleLs();
                } else if (command.equalsIgnoreCase(EXIT)) {
                    handleExit();
                } else {
                    handleOther(true);
                }
            } else {
                handleOther(false);
            }
        }
    
        /**
         * Returns the path to the given file by prepending the filebase.
         * 
         * @param file
         *            target filename
         * @return full local path to file
         */
        protected String getFilePath(String file) {
            return MessageFormat.format("{0}{1}", fileBase, file);
        }
    
        /**
         * Read the given file from disk into a byte array.
         * 
         * @param file
         *            the target file
         * @return byte array containing file contents
         */
        protected byte[] readFile(File file) {
            byte[] data = new byte[(int) file.length()];
    
            try {
                System.out.printf("Loading %s ... ", file);
                FileInputStream fis = new FileInputStream(file);
                int amt = fis.read(data, 0, data.length);
                fis.close();
                System.out.printf("done (%d bytes).\n", amt);
            } catch (IOException ioe) {
                System.err.printf("Error reading file: %s\n", ioe);
            }
    
            return data;
        }
    
        /**
         * Writes a file to the filebase.
         * 
         * @param data
         *            Raw bytes of a file
         * @param filename
         *            the name to give the new file.
         * @throws IOException
         */
        protected void storeFile(byte[] data, String filename) throws IOException {
            String toWrite = getFilePath(filename);
            System.out.printf("Storing file at %s... ", toWrite);
            FileOutputStream fileOut = new FileOutputStream(toWrite);
            fileOut.write(data);
            fileOut.flush();
            fileOut.close();
            System.out.printf("done.\n");
        }
    
        /**
         * Receives a byte[] as individual ints.
         * 
         * @return a byte[] value
         */
        protected byte[] receiveData() throws IOException {
            // get amount of bytes expected
            int byteAmt = new Integer(lineIn.readLine());
            byte[] toReturn = new byte[byteAmt];
    
            // receive the bytes
            for (int i = 0; i < byteAmt; i++) {
                toReturn[i] = new Integer(lineIn.readLine()).byteValue();
            }
    
            return toReturn;
        }
    
        /**
         * Transmits bytes one by one as ints.
         * 
         * @param bytes
         *            a byte[] value
         */
        protected void sendData(byte[] bytes) {
            // tell receiver # of bytes to expect
            lineOut.println(bytes.length);
    
            // send each byte as ints, one-by-one
            for (byte aB : bytes) {
                lineOut.println(new Byte(aB).intValue());
            }
        }
    
        /**
         * Sends the string to over the socket.
         * 
         * @param message
         */
        protected void sendMessage(String message) {
            sendData(message.getBytes());
        }
    
        /**
         * Receives a string from the socket.
         * 
         * @return string received
         */
        protected String receiveMessage() throws IOException {
            return new String(receiveData());
        }
    
        // ----------------------------------------------------------------------
        // ABSTRACT METHODS - inherited & implemented by client and server
        // ----------------------------------------------------------------------
    
        /**
         * Uploads a client-side file to the server.
         * 
         * @param filename
         */
        abstract protected void handlePut(String filename);
    
        /**
         * Downloads a file from the server
         * 
         * @param filename
         */
        abstract protected void handleGet(String filename);
    
        /**
         * Lists the files available on the server.
         */
        abstract protected void handleLs();
    
        /**
         * Ends an FTP session, tearing down the server-client connection.
         */
        abstract protected void handleExit();
    
        /**
         * Models receiving bad input.
         * 
         * @param invalidCmd
         */
        abstract protected void handleOther(boolean invalidCmd);
    
    }
    
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.text.MessageFormat;
    import java.util.StringTokenizer;
    
    /**
     * A pseudo-FTP client. Connects to server and enters a control loop which
     * enables it to query the server.
    
    
    public class FTPClient extends FTPApplication {
        protected int port;
        protected InetAddress ip;
    
        // ----------------------------------------------------------------------
        // CONSTRUCTOR
        // ----------------------------------------------------------------------
    
        /**
         * Default constructor.
         * 
         * @param port
         *            The port to connect to on the server.
         * @param ip
         *            The server's IP address
         * @param fileBase
         *            The directory from which the client will read and write.
         */
        public FTPClient(int port, InetAddress ip, String fileBase) {
            super(fileBase);
            this.port = port;
            this.ip = ip;
            System.out.printf("Working out of %s\n", this.fileBase);
        }
    
        // ----------------------------------------------------------------------
        // PRIVATE METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Prints usage message to the console.
         */
        private static void printUsage() {
            System.out.printf("Usage: FTPClient -i <ip> -p <port> [options]\n\n");
            System.out.printf("\tWhere valid options include: \n");
            System.out.printf("\t\t -h \t Prints usage \n");
            System.out.printf("\t\t -d \t File directory \n");
        }
    
        // ----------------------------------------------------------------------
        // INHERITED, PROTECTED METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Checks that the specified file is valid, then transmits the file's name,
         * size, and data. After transmission, the client waits for a response from
         * the server.
         * 
         * @param filename
         *            Name of the file to send.
         */
        protected void handlePut(String filename) {
            // confirm existence of file
            File file = new File(getFilePath(filename));
            if (!file.exists()) {
                System.err.printf("%s does not exist.\n", file);
                handleOther(false);
            } else {
                try {
                    // send filename
                    System.out.printf("Sending filename ... ");
                    sendMessage(MessageFormat.format("{0} {1}", PUT, filename));
                    System.out.printf("done.\n");
    
                    // send data
                    byte[] data = readFile(file);
                    sendData(data);
    
                    // await reply
                    System.out.printf("Server reply: ");
                    String reply = receiveMessage();
                    System.out.printf("%s\n", reply);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
    
        /**
         * Sends the request to the server, receives the length of the file (if it
         * exists), and receives the file's data.
         * 
         * @param filename
         *            Name of the file to receive.
         */
        protected void handleGet(String filename) {
            try {
                // request file
                sendMessage(MessageFormat.format("{0} {1}", GET, filename));
    
                // receive file length
                System.out.printf("Receiving length ... ");
                String input = receiveMessage();
                long length = (input != null) ? Long.valueOf(input) : ERROR;
                System.out.printf("done.\n");
    
                // in case the file doesn't exist on the server side
                if (length == ERROR) {
                    System.out.printf("Server: %s does not exist.\n", filename);
                } else {
                    // GET DATA
                    byte[] data = receiveData();
    
                    // SAVE DATA
                    storeFile(data, filename);
                    System.out.printf("Received %s OK.\n", filename);
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Sends the listing request to the server, receives the amount of files
         * there are, and receives each filename.
         */
        protected void handleLs() {
            try {
                // request listing
                sendMessage(LS);
    
                // receive number of files
                String input = receiveMessage();
                int fileAmt = input != null ? Integer.valueOf(input) : ERROR;
    
                // receive and print names of files
                if (fileAmt != ERROR) {
                    for (int i = 0; i < fileAmt; i++) {
                        System.out.printf("\t%s\n", receiveMessage());
                    }
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Models receiving a null or invalid command
         * 
         * @param invalidCmd
         *            If true, prints message stating that an invalid cmd was
         *            received.
         */
        protected void handleOther(boolean invalidCmd) {
            sendMessage("\n");
            if (invalidCmd) {
                System.err.printf("Invalid command.\n");
            }
        }
    
        /**
         * Sends an exit signal to the server and terminates the connection.
         */
        protected void handleExit() {
            sendMessage(EXIT);
            exitRecieved = true;
            terminate();
        }
    
        // ----------------------------------------------------------------------
        // PUBLIC METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Establish connection with server and create I/O objects.
         * 
         * @return true if connection was established successfully.
         */
        public boolean connect() {
            boolean success = false;
    
            try {
                System.out.printf("Connecting to %s:%d ... ", ip, port);
                socket = new Socket(ip, port);
                setUpIO();
                success = true;
                System.out.printf("Established.\n");
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return success;
        }
    
        /**
         * Begins loop that allows client to send commands to the server.
         */
        public void queryServer() {
            if (lineIn == null || lineOut == null) {
                System.err.printf("Cannot query server, IO has not been set up\n");
            } else {
                try {
                    String serverReply;
                    String userInput;
                    StringTokenizer args;
                    InputStreamReader input = new InputStreamReader(System.in);
                    BufferedReader console = new BufferedReader(input);
    
                    // client-side control loop
                    while (!exitRecieved) {
                        // Wait for PROMPT
                        serverReply = receiveMessage();
                        System.out.printf("%s", serverReply);
    
                        // ACCEPT & PROCESS USER INPUT
                        userInput = console.readLine();
                        userInput = userInput == null ? "" : userInput;
                        args = new StringTokenizer(userInput);
                        processCommand(args);
                    }
    
                    // clean up
                    console.close();
                    input.close();
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * Driver for FTPClient
         * 
         * @param args
         *            Command-line arguments
         */
        public static void main(String[] args) {
            int port = -1;
            String directory = System.getProperty(FTPApplication.DEFAULT_FILEBASE);
            InetAddress ip = null;
    
            // Process arguments
            boolean helpRequested = false;
            for (int index = 0; !helpRequested && index < args.length; index++) {
                if (args[index].length() == 2 & args[index].charAt(0) == '-') {
                    switch (args[index].charAt(1)) {
                    case 'p':
                        if (index + 1 >= args.length) {
                            System.err.println("Port number expected.");
                            helpRequested = true;
                        } else {
                            port = Integer.valueOf(args[++index]);
                        }
                        break;
                    case 'h':
                        helpRequested = true;
                        break;
                    case 'd':
                        if (index + 1 >= args.length) {
                            System.err.println("Directory expected.");
                            helpRequested = true;
                        } else {
                            File path = new File(args[++index]);
                            if (path.exists()) {
                                directory = args[index];
                            } else {
                                System.err.println("Invalid directory");
                                helpRequested = true;
                            }
                        }
                        break;
                    case 'i':
                        if (index + 1 >= args.length) {
                            System.err.println("IP address expected.");
                            helpRequested = true;
                        } else {
                            try {
                                ip = InetAddress.getByName(args[++index]);
                            } catch (UnknownHostException uhe) {
                                System.err.printf("Bad address: %s\n", uhe);
                                helpRequested = true;
                            }
                        }
                        break;
                    default:
                        helpRequested = true;
                        break;
                    }
                } else {
                    helpRequested = true;
                }
            }
    
            // Begin execution
            if (helpRequested || port == -1 || ip == null) {
                printUsage();
            } else {
                FTPClient client = new FTPClient(port, ip, directory);
                if (client.connect()) {
                    client.queryServer();
                }
            }
        }
    
    }
    
    
    import java.io.File;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * A pseudo FTP server. Accepts client connection and initiates a session.
    
    
    public class FTPServer {
        protected int port;
        protected String fileBase;
    
        // ----------------------------------------------------------------------
        // CONSTRUCTOR
        // ----------------------------------------------------------------------
    
        /**
         * Default constructor.
         * 
         * @param port
         *            Port which the server will listen on.
         * @param fileBase
         *            The path to the directory from which files will be served
         */
        public FTPServer(int port, String fileBase) {
            this.port = port;
            this.fileBase = fileBase;
        }
    
        // ----------------------------------------------------------------------
        // PRIVATE METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Prints usage message to the console.
         */
        private static void printUsage() {
            System.out.printf("Usage: FTPServer -p <port> [options] \n\n");
            System.out.printf("\tWhere valid options include: \n");
            System.out.printf("\t\t -h \t Prints usage \n");
            System.out.printf("\t\t -d \t File directory \n");
        }
    
        // ----------------------------------------------------------------------
        // PUBLIC METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Performs a passive open and accepts a client. ServerSession objects are
         * instantiated to serve client requests.
         */
        public void acceptClients() {
            try {
                // initiate server socket
                System.out.printf("Creating socket ... ");
                ServerSocket serverSocket = new ServerSocket(port);
                serverSocket.setSoTimeout(FTPApplication.SOCKET_TIMEOUT);
                System.out.printf("Bound to %s:%s \n", InetAddress.getLocalHost(),
                        serverSocket.getLocalPort());
    
                // listen for clients
                System.out.printf("Listening for connections ... ");
                Socket clientSocket = serverSocket.accept();
                System.out.printf("Accepted client from %s\n", clientSocket);
    
                // SERVE THE CLIENT
                ServerSession session = new ServerSession(clientSocket, fileBase);
                session.serveClient();
    
                // clean up
                System.out.printf("Closing socket ... ");
                serverSocket.close();
                System.out.printf("done.");
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Driver for the FTPServer.
         * 
         * @param args
         *            command line arguments
         */
        public static void main(String[] args) {
            int port = -1;
            String directory = System.getProperty(FTPApplication.DEFAULT_FILEBASE);
    
            // Process arguments
            boolean helpRequested = false;
            for (int index = 0; !helpRequested & index < args.length; index++) {
                if (args[index].length() == 2 & args[index].charAt(0) == '-') {
                    switch (args[index].charAt(1)) {
                    case 'p':
                        if (index + 1 >= args.length) {
                            System.err.println("Port number expected.");
                            helpRequested = true;
                        } else {
                            port = Integer.valueOf(args[++index]);
                        }
                        break;
                    case 'h':
                        helpRequested = true;
                        break;
                    case 'd':
                        if (index + 1 >= args.length) {
                            System.err.println("Directory expected.");
                            helpRequested = true;
                        } else {
                            File path = new File(args[++index]);
                            if (path.exists()) {
                                directory = args[index];
                            } else {
                                System.err.println("Invalid directory");
                                helpRequested = true;
                            }
                        }
                        break;
                    default:
                        helpRequested = true;
                        break;
                    }
                } else {
                    helpRequested = true;
                }
    
            }
    
            // Begin execution
            if (helpRequested || port == -1) {
                printUsage();
            } else {
                FTPServer server = new FTPServer(port, directory);
                server.acceptClients();
            }
        }
    
    }
    
    
    import java.io.File;
    import java.io.IOException;
    import java.net.Socket;
    import java.util.StringTokenizer;
    
    
    public class ServerSession extends FTPApplication {
        private static final String PROMPT = "secFTP>";
    
        // ----------------------------------------------------------------------
        // CONSTRUCTOR
        // ----------------------------------------------------------------------
    
        /**
         * Default constructor. Sets up I/O objects associated with the socket.
         * 
         * @param socket
         *            Network endpoint connected to a client.
         * @param filePath
         *            Path to the file base.
         */
        public ServerSession(Socket socket, String filePath) throws IOException {
            super(filePath);
            System.out.printf("Serving files out of %s. \n", fileBase);
            this.socket = socket;
            setUpIO();
        }
    
        // ----------------------------------------------------------------------
        // PROTECTED METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Receives the name, length, and data of the file to upload. The data
         * received is written to a file and a status message is sent.
         * 
         * @param filename
         *            the name of the file to upload.
         */
        protected void handlePut(String filename) {
            boolean success = false;
    
            try {
                System.out.printf("Receiving %s\n", filename);
    
                // GET DATA
                byte[] data = receiveData();
    
                // SAVE DATA
                if (data != null) {
                    storeFile(data, filename);
                    success = true;
                }
    
            } catch (IOException ioe) {
                System.err.printf("I/O error receiving file: %s\n", ioe);
            } catch (NumberFormatException nfe) {
                System.err.printf("Invalid length specified: %s\n", nfe);
            }
    
            // SEND REPLY
            System.out.printf("Sending reply ... ");
            String message = success ? "PUT OK" : "PUT FAILED";
            sendMessage(message);
            System.out.printf("done.\n");
        }
    
        /**
         * Determines if the specified file exists, and sends the file's length and
         * data.
         * 
         * @param filename
         *            name of the file to transmit.
         */
        protected void handleGet(String filename) {
            System.out.printf("Preparing to send %s ... \n", filename);
    
            // CHECK EXISTANCE OF FILE, AND SEND LENGTH
            File file = new File(getFilePath(filename));
            if (!file.exists()) {
                System.err.printf("%s does not exist.\n", file);
                sendMessage(String.valueOf(ERROR));
            } else {
                // send length
                System.out.printf("Sending length ... ");
                sendMessage(String.valueOf(file.length()));
                System.out.printf("done.\n");
    
                // send data
                byte[] data = readFile(file);
                sendData(data);
            }
        }
    
        /**
         * Determines the available files, then sends the number, followed by names
         * of them.
         */
        protected void handleLs() {
            System.out.printf("Listing available files.\n");
    
            File[] availableFiles = new File(fileBase).listFiles();
    
            if (availableFiles == null) {
                System.err.printf("%s is not a directory.\n", fileBase);
                sendMessage(String.valueOf(ERROR));
            } else {
                sendMessage(String.valueOf(availableFiles.length));
    
                /* send each file name */
                for (File file : availableFiles) {
                    sendMessage(file.getName());
                }
            }
        }
    
        /**
         * Models receiving an invalid or null command: ignore it.
         * 
         * @param invalidCmd
         */
        protected void handleOther(boolean invalidCmd) {
            // do nothing
        }
    
        /**
         * Terminates connection to client, toggles control loop variable.
         */
        protected void handleExit() {
            exitRecieved = true;
            terminate();
        }
    
        // ----------------------------------------------------------------------
        // PUBLIC METHODS
        // ----------------------------------------------------------------------
    
        /**
         * Initiates the service loop that serves client requests.
         */
        public void serveClient() {
            if (lineIn == null || lineOut == null) {
                System.err.printf("I/O has not been set up.\n");
            } else {
                try {
                    String clientRequest;
                    StringTokenizer args;
    
                    // control loop, receiving client requests
                    while (!exitRecieved) {
                        // PRESENT PROMPT
                        sendMessage(PROMPT);
    
                        // ACCEPT & PROCESS INPUT
                        clientRequest = receiveMessage();
                        clientRequest = clientRequest == null ? "" : clientRequest;
                        args = new StringTokenizer(clientRequest);
                        processCommand(args);
                    }
    
                } catch (IOException ioe) {
                    System.err.printf("IO Error receiving client input: %s\n", ioe);
                }
            }
        }
    
    }

    I need to make sure that:

    * Ensure that any user-supplied information is verified as safe before it is acted upon.
    * Harden appropriate classes and/or members against improper data access, extension, or modification.
    * Review the exception handling throughout, and ensure that each exception is properly reported
    and cleanly recovered from.

 0 Answer(s)

Sign In
                           OR                           
                           OR                           
Register

Sign up using

                           OR                           
Forgot Password
Fill out the form below and instructions to reset your password will be emailed to you:
Reset Password
Fill out the form below and reset your password: