網路專題:電子商務交易安全規範 Sftp傳輸機制範例

網路專題:電子商務交易安全規範 Sftp傳輸機制範例

four bots

大四學生畢業之前都需製作專題報告,由於老師專業屬於資訊管理方面,提出一個企業之間時常遇到的實例,這是網路上都搜尋到的資料,在學生角度上無法體驗企業員工為何在資料交換方面,該如何進行傳輸資料交換方式,在此提出Java 程式語言為Client 為例,以及兩套軟體模擬FTP Server(FileZilla Server) 和SFTP Server(Rebex Tiny SFTP Server),作為Server 端接收檔案,可確認在Java Code 確實傳輸成功或失敗。

檔案傳輸安全的議題

企業如何使用FTP: 檔案傳輸管理

FTP(File Transfer Protocol, 檔案傳輸協定)是網路上最常使用的檔案傳輸或交換方法. 每天,數以萬計的電子檔案在世界各地的企業/政府單位/組織間交換,這些電子檔案一定包含了關鍵資料如企業營運的客戶資料、人事資料、財務資料等等. 但很少管理者了解FTP的風險:很難控制及不安全. 現今駭客盛行, 企業經營的風險與各種法規的要求都直指必須重新檢視如何安全的傳輸檔案。…..

檔案傳輸(File Transfer)安全與自動化解決方法

企業經常需要與外部使用者(客戶及合作夥伴)交換檔案, 最常使用的工具就是eMail及FTP檔案傳輸了. 但是當這些檔案涉及機密或需自動化處理, 就需慎選適當的工具了….

一個有效率及安全的FTP伺服器應允許您的交易夥伴連接到您組織, 在一個安全與可管理的環境下與您交換文件。同樣重要的是,你的FTP伺服器也應產生詳細的稽核日誌(Audit log),以滿足安全法規要求

GoAnywhere secure FTP server 是一個強大的企業級的文件共享解決方案,包括一個整合的 SFTP Server,FTPS Server和 HTTPS Server。

滿足日益增長的需求: 提供最好的服務是最重要的,所以你需要一個安全的FTP伺服器,提供業界標準的的檔案傳輸協議(FTP,SFTP,FTPS,HTTPS,AS2)和加密標準如AES.也要能支持高度可擴展性, 它應該支持多種平台包括Windows,Linux,VMware和IBM i系統,AIX,UNIX和Solaris,以及包括集群(Cluster)和負載均衡(Load Balance),以提高高可用性。

採取控制: 遠端管理和監控是透過 GoAnywhere直覺的瀏覽器界面。它有強大的安全性包括Active Directory(AD)和LDAP身份驗證,蠻力和DoS攻擊監控器,密碼策略,IP篩選器和更多。整合的密鑰管理(Key Management)包含導入現有密鑰和憑證。傳輸可以使用SSL/ TLS或SSH加密與FIPS140-2驗證算法。稽核日誌記錄了所有檔案傳輸的每一步驟改善工作流程: 節省時間,透過各種靈活的GoAnywhere功能更有效地管理檔案傳輸。例如,事件觸發器(Trigger), 當合作夥伴下載或上傳檔案時, 可以自動發送電子郵件警報或調用自定程式。一個直觀的Web客戶端界面允許使用瀏覽器簡單的點對點檔案傳輸。用戶還可以安全地直接從Outlook或安全的Web表單發送大檔案。


Java For FTP Library:commons-net-3.8.0.jar

<dependency>
	<groupId>commons-net</groupId>
	<artifactId>commons-net</artifactId>
	<version>3.8.0</version>
</dependency>
package com.bots.four.ftp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FTPClientTest {

    public static void main(String[] args) {

        int port = 21;
        String username = "mFtp";
        String password = "123456";
        String hostName = "127.0.0.1";
        String fileName = "testuploadfile.txt";
        Long datetime = System.currentTimeMillis();
        String currentPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();

        try {

            /* ftp 連線測試 (S)------------------------------------------------------------*/
            connectTest(hostName, port, username, password);
            System.out.println("==========================================================================================");

            /* ftp 檔案清單 (S)------------------------------------------------------------*/
            fileListTest(hostName, port, username, password);
            System.out.println("==========================================================================================");

            /* ftp 上傳檔案 (S)------------------------------------------------------------*/
            String[] buffer = fileName.split("\\.", 0);/* 注意: .、$、|和*等轉義字符,必須得加\\。*/
            // System.out.println("buffer = " + buffer.length);
            String newFileName = buffer[0] + "_" + datetime + "." + buffer[1];
            // System.out.println("newFileName = " + newFileName);
            InputStream is = FTPClientTest.class.getResourceAsStream("/" + fileName);
            // System.out.println("is = " + (is != null));
            uploadFileTest(hostName, port, username, password, newFileName, is);
            System.out.println("==========================================================================================");

            /* ftp 檔案下載 (S)------------------------------------------------------------*/
            currentPath = currentPath + "/temp";
            // System.out.println("currentPath = " + currentPath);
            File path = new File(currentPath);
            if (!path.exists()) {
                path.mkdir();
            }

            try {
                downloadFileTest(hostName, port, username, password, newFileName, path);
            } finally {
                path.delete();
            }
            System.out.println("==========================================================================================");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("error: " + e.getMessage());
        }
    }

    private static void connectTest(String hostName, int port, String userName, String userPassword) {
        System.out.println("connectTest(String hostName, int port, String userName, String userPassword)");

        FTPClient ftp = null;
        try {
            ftp = new FTPClient();

            /* 指定連線Ftp Server 位址*/
            ftp.connect(hostName, port);
            int replyCode = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                System.out.println("連線到FTP Server 失敗!!!");
            } else {

                /* 登入者帳密*/
                if (ftp.login(userName, userPassword) == false) {
                    System.out.println("使用者名稱或密碼錯誤!!!");
                } else {
                    System.out.println("FTP Server 連線成功。");
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能錯誤,請正確配置。");
        } catch (IOException ex) {
            Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (ftp != null) {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private static void fileListTest(String hostName, int port, String userName, String userPassword) {
        System.out.println("fileListTest(String hostName, int port, String userName, String userPassword)");

        FTPClient ftp = null;
        try {
            ftp = new FTPClient();

            /* 指定連線Ftp Server 位址*/
            ftp.connect(hostName, port);
            int replyCode = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                System.out.println("連線到FTP Server 失敗!!!");
            } else {

                /* 登入者帳密*/
                if (ftp.login(userName, userPassword) == false) {
                    System.out.println("使用者名稱或密碼錯誤!!!");
                } else {

                    // lists files and directories in the current working directory
                    FTPFile[] files = ftp.listFiles();
                    for (FTPFile file : files) {
                        if (file.isDirectory()) {
                            System.out.println("[" + file.getName() + "]");
                        } else {
                            System.out.println(file.getName());
                        }
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能錯誤,請正確配置。");
        } catch (IOException ex) {
            Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (ftp != null) {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private static void uploadFileTest(String hostName, int port, String userName, String userPassword, String fileName, InputStream is) {
        System.out.println("uploadFileTest(String hostName, int port, String userName, String userPassword, String fileName, InputStream is)");

        FTPClient ftp = null;
        try {
            ftp = new FTPClient();

            /* 指定連線Ftp Server 位址*/
            ftp.connect(hostName, port);
            int replyCode = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                System.out.println("連線到FTP Server 失敗!!!");
            } else {

                /* 登入者帳密*/
                if (ftp.login(userName, userPassword) == false) {
                    System.out.println("使用者名稱或密碼錯誤!!!");
                } else {

                    ftp.setControlEncoding("UTF-8");// 中文支援
                    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                    ftp.enterLocalPassiveMode();
                    // ftp.changeWorkingDirectory(ftpPath);
                    ftp.storeFile(fileName, is);
                    System.out.println("檔案上傳成功。");
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能錯誤,請正確配置。");
        } catch (IOException e) {
            Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (ftp != null) {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private static void downloadFileTest(String hostName, int port, String userName, String userPassword, String fileName, File localPath) {
        System.out.println("downloadFileTest(String hostName, int port, String userName, String userPassword, String fileName, File localPath)");

        File file = null;
        FTPClient ftp = null;
        OutputStream os = null;
        try {
            ftp = new FTPClient();

            /* 指定連線Ftp Server 位址*/
            ftp.connect(hostName, port);
            int replyCode = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                System.out.println("連線到FTP Server 失敗!!!");
            } else {

                /* 登入者帳密*/
                if (ftp.login(userName, userPassword) == false) {
                    System.out.println("使用者名稱或密碼錯誤!!!");
                } else {

                    ftp.setControlEncoding("UTF-8");// 中文支援
                    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                    ftp.enterLocalPassiveMode();
                    // ftp.changeWorkingDirectory(ftpPath);
                    file = new File(localPath + "/" + fileName);
                    os = new FileOutputStream(file);
                    ftp.retrieveFile(fileName, os);

                    if (!file.exists()) {
                        System.out.println("檔案下載失敗!!!");
                    } else {
                        System.out.println("檔案下載成功。");
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能錯誤,請正確配置。");
        } catch (IOException e) {
            Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (file != null && file.exists()) {
                file.delete();
            }
            if (ftp != null) {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    Logger.getLogger(FTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}

程式執行結果:

FileZilla Server:建議檔案下載連結,版本:0.9.60.2,語言:English


什麼是SFTP ?

SFTP(SSH File Transfer Protocol,也稱Secret File Transfer Protocol)是一種安全的文件傳輸協議,一種通過網絡傳輸文件的安全方法;它確保使用私有和安全的數據流來安全地傳輸數據。
SFTP傳輸文件的過程,如下圖:

SFTP要求客戶端用戶必須由服務器進行身份驗證,並且數據傳輸必須通過安全通道(SSH)進行,即不傳輸明文密碼或文件數據。它允許對遠程文件執行各種操作,有點像遠程文件系統協議。SFTP允許從暫停傳輸,目錄列表和遠程文件刪除等操作中恢復。

Java For SFTP Library: jsch.jar

操作手冊網址:http://www.jcraft.com/jsch/examples/

<dependency>
	<groupId>commons-net</groupId>
	<artifactId>commons-net</artifactId>
	<version>3.8.0</version>
</dependency>
package com.bots.four.sftp;

public class SftpConfig {

    /**
     * sftp 伺服器地址
     */
    String host;
    /**
     * sftp 伺服器埠
     */
    int port;
    /**
     * sftp伺服器登陸使用者名稱
     */
    String user;
    /**
     * sftp 伺服器登陸密碼 密碼和私鑰二選一
     */
    String password;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

package com.bots.four.sftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SFTPClientTest {

    public static void main(String[] args) {

        SftpConfig vo = new SftpConfig();

        vo.setPort(22);
        vo.setHost("192.168.184.128");
        vo.setUser("tester");
        vo.setPassword("!qaz2wsx");

        String fileName = "testuploadfile.txt";
        Long datetime = System.currentTimeMillis();
        String currentPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();

        ChannelSftp channelSftp = null;

        try {

            channelSftp = setupJsch(vo);

            /* sftp 連線測試 (S)------------------------------------------------------------*/
            connectTest(channelSftp);

            /* sftp 檔案清單 (S)------------------------------------------------------------*/
            fileListTest(channelSftp);

            /* ftp 上傳檔案 (S)------------------------------------------------------------*/
            String[] buffer = fileName.split("\\.", 0);/* 注意: .、$、|和*等轉義字符,必須得加\\。*/
            // System.out.println("buffer = " + buffer.length);
            String newFileName = buffer[0] + "_" + datetime + "." + buffer[1];
            // System.out.println("newFileName = " + newFileName);
            InputStream is = SFTPClientTest.class.getResourceAsStream("/" + fileName);
            // System.out.println("is = " + (is != null));
            uploadFileTest(channelSftp, newFileName, is);

            /* sftp 檔案下載 (S)------------------------------------------------------------*/
            currentPath = currentPath + "/temp";
            // System.out.println("currentPath = " + currentPath);
            File path = new File(currentPath);
            if (!path.exists()) {
                path.mkdir();
            }

            try {
                downloadFileTest(channelSftp, newFileName, path);
            } finally {
                path.delete();
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("error: " + e.getMessage());
        } finally {
            if (channelSftp != null) {
                channelSftp.exit();
                channelSftp.disconnect();
            }
        }
    }

    private static ChannelSftp setupJsch(SftpConfig param) {
        JSch jsch = new JSch();
        Session session;
        try {
            session = jsch.getSession(param.getUser(), param.getHost(), param.getPort());
            Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            session.setPassword(param.getPassword());
            session.connect();
            return (ChannelSftp) session.openChannel("sftp");
        } catch (JSchException e) {
            e.printStackTrace();
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, e);
            throw new RuntimeException(e);
        }
    }

    private static void connectTest(ChannelSftp sftp) {
        System.out.println("connectTest(ChannelSftp sftp)");
        try {
            sftp.connect();
            System.out.println("SFTP Server連線成功。");
        } catch (JSchException e) {
            System.out.println("連線到SFTP Server 失敗!!!");
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, e);
        }
        System.out.println("==========================================================================================");
    }

    private static void fileListTest(ChannelSftp sftp) {
        System.out.println("fileListTest(ChannelSftp sftp)");
        try {
            Vector<LsEntry> files = sftp.ls("/");
            for (LsEntry file : files) {
                String fileName = file.getFilename();
                if (!".".equals(fileName) && !"..".equals(fileName)) {
                    System.out.println(String.format("File - %s", fileName));
                }
            }
        } catch (SftpException ex) {
            System.out.println("登入連線路徑失敗!!!");
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("==========================================================================================");
    }

    private static void uploadFileTest(ChannelSftp sftp, String newFileName, InputStream is) {
        System.out.println("uploadFileTest(ChannelSftp sftp, String newFileName, InputStream is)");
        try {
            sftp.put(is, newFileName);
            System.out.println("檔案上傳成功。");
        } catch (SftpException ex) {
            System.out.println("SFtp Upload Fail!!!");
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("==========================================================================================");
    }

    private static void downloadFileTest(ChannelSftp sftp, String fileName, File localPath) {
        System.out.println("downloadFileTest(ChannelSftp sftp, String fileName, File localPath)");

        File file = null;
        OutputStream os = null;
        try {
            file = new File(localPath + "/" + fileName);
            os = new FileOutputStream(file);
            sftp.get(fileName, os);
            System.out.println("檔案下載成功。");
        } catch (FileNotFoundException e) {
            System.out.println("local file Fail!!!");
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, e);
        } catch (SftpException e) {
            System.out.println("SFtp Download Fail!!!");
            Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException ex) {
                    Logger.getLogger(SFTPClientTest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            if (file != null && file.exists()) {
                file.delete();
            }
        }
        System.out.println("==========================================================================================");
    }

}

程式執行結果:

Rebex Tiny SFTP Server: 建議檔案下載連結

Rebex Tiny SFTP Server 介面

SFTP和FTP之間的區別?

SFTP 和FTP非常相似,都支持批量傳輸(一次傳輸多個文件),文件夾/目錄導航,文件移動,文件夾/目錄創建,文件刪除等。但還是存在著差異,以下我們來看看SFTP 和FTP 之間的區別:
1、安全通道:FTP 不提供任何安全通道來在主機之間傳輸文件;而,SFTP協議提供了一個安全通道,用於在網絡上的主機之間傳輸文件。
2、使用的協議:FTP使用TCP/IP協議。而SFTP 是SSH 協議的一部分,它是一種遠程登錄信息。
3、鏈接方式:FTP 使用TCP 端口21上的控制連接建立連接。而SFTP 是在客戶端和服務器之間通過SSH協議(TCP端口22)建立的安全連接來傳輸文件。
4、安全性:FTP 密碼和數據以純文本格式發送,大多數情況下是不加密的,安全性不高。而SFTP 會在發送之前加密數據,二進制的形式傳遞,是無法”原始資料” 閱讀的,安全性較高。
以上就是SFTP是什麼與FTP之間有什麼區別的詳細內容。