C Sharpとネットワーク - SFTP

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

SFTP(Secure File Transfer Protocol)は、SSH(Secure Shell)プロトコルを使用してファイルを安全に転送するためのプロトコルの一種である。

  • セキュアな通信
    SFTPは、データ転送の際にSSHを使用するため、通信は暗号化され、セキュアである。
    データの盗聴や改竄から保護されるため、非常に安全な転送方法とされている。

  • ポート番号
    SFTPは、SSHのポート番号を使用する。
    しかし、SFTP専用のポートを使用することもできる。

  • 利用方法
    SFTPは、コマンドラインインターフェースやGUIツールを通じて使用できる。
    一般的なSFTPクライアントには、FileZilla、WinSCP、Cyberduck等が存在する。

  • アクセス権の管理
    SFTPは、SSHの認証メカニズムを使用するため、ユーザは、ユーザ名、パスワード、鍵を使用してサーバに接続する。
    アクセス権はSSHの権限設定によって管理される。

  • バッチ処理
    SFTPはバッチ処理にも適している。
    スクリプトを使用して、定期的なファイル転送や自動化されたタスクを実行できる。


C#において使用できるSSHライブラリとして、SSH.NET等がある。



処理の流れ

  1. 認証方法のインスタンスを生成する。
    公開鍵認証またはパスワード認証を選択する。
    公開鍵認証において、SSH.NETはppk形式の鍵ファイルをサポートしていない。 (例外が発生する)
    そのため、あらかじめ、ppk形式をOpenSSH形式に変換する必要があることに注意する。

  2. 接続情報のインスタンスを生成する。
    生成した認証方法のインスタンスをコンストラクタの引数で渡す。

  3. sftpClientのインスタンスを生成する。
    接続情報のインスタンスをコンストラクタの引数に渡す。

  4. 処理を記述する。
    (ダウンロード処理やアップロード処理)


以下に示すサンプルコードでは、公開鍵認証を用いてユーザディレクトリのパスを取得するメソッドSystem.Environment.GetFolderPathを使用しているが、
Linuxでも問題なくユーザディレクトリ配下のパスを取得できる。


単一のファイルのダウンロード / アップロード

 using System;
 using System.IO;
 using Renci.SshNet;
 
 class SFTP
 {
    static void Main(string[] args)
    {
       // 公開鍵認証の場合
       // 例としてユーザディレクトリ配下の.sshディレクトリ内のsecret_key.pemを秘密鍵として使用
       string secretKeyPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", 
                                          "secret_key.pem");
 
       // 公開鍵にパスフレーズが存在する場合
       var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                           new PrivateKeyFile(secretKeyPath, "<パスフレーズ>"));
 
       // 公開鍵にパスフレーズが無い場合
       //var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
       //                                                    new PrivateKeyFile(secretKeyPath, ""));
 
       // パスワード認証の場合
       //var authMethod = new PasswordAuthenticationMethod("<リモートPCのユーザ名>",
       //                                                  "<リモートPCのユーザ名のパスワード>");
 
       // 接続情報のインスタンス生成
       var connectionInfo = new ConnectionInfo("<リモートPCのIPアドレス または ホスト名>",
                                               <ト番号>,
                                               "<リモートPCのユーザ名>",
                                               authMethod);
 
       using (var client = new SftpClient(connectionInfo))
       {
          // SSH接続を行う
          client.Connect();
 
          // ユーザディレクトリに移動
          client.ChangeDirectory("/home/username");
 
          // test.txtファイルを読み込み専用で開く
          using (var fs = System.IO.File.OpenRead("test.txt"))
          {
             // test.txtファイルをアップロード(trueを指定すると上書き可能となる)
             client.UploadFile(fs, "test.txt", true);
          }
 
          // SSH接続を切断
          client.Disconnect();

          // SSH接続を行う
          client.Connect();
 
          // ユーザディレクトリに移動
          client.ChangeDirectory("/home/username");
 
          // test.txtファイルを書き込み専用で開く
          using (var fs = System.IO.File.OpenWrite("test.txt"))
          {
                // test.txtファイルをダウンロード
                client.DownloadFile("test.txt", fs);
          }
 
          // SSH接続を切断
          client.Disconnect();
       }
    }
 }



複数のファイルのダウンロード

SSH.NETはディレクトリ単位でダウンロードできない。
そのため、ディレクトリ内の全てのファイルをダウンロードする場青は、サーバ上にあるディレクトリのパスを指定して、個別にダウンロードする必要がある。

以下の例では、リモートPC上にある/home/username/testディレクトリ内のファイルを全てダウンロードしている。

 // ...略
 
 client.Connect();
 
 var files = client.ListDirectory("/home/username/test").Where(x => x.Name != "." && x.Name != "..");
 foreach (var file in files)
 {
    using (var fs = System.IO.File.OpenWrite(file.Name))
    {
       client.DownloadFile(file.FullName, fs);
    }
 }
 
 client.Disconnect();
 
 // ...略



複数のファイルのアップロード

以下の例では、アップロードするファイルのパスを配列で指定して、複数のファイルをリモートPC上にある/home/usernameディレクトリアップロードしている。
ループ処理内において、1つずつファイルを読み込み、UploadFileメソッドを使用する。

 using System;
 using System.IO;
 using Renci.SshNet;
 
 class SftpUploadMultipleFiles
 {
    static void Main(string[] args)
    {
       // 公開鍵認証の場合
       // 例としてユーザディレクトリ配下の.sshディレクトリ内のsecret_key.pemを秘密鍵として使用
       string secretKeyPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh", "secret_key.pem");
       var authMethod = new PrivateKeyAuthenticationMethod("username", new PrivateKeyFile(secretKeyPath, "finger_print"));
 
       // 公開鍵にパスフレーズが存在する場合
       var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                           new PrivateKeyFile(secretKeyPath, "<パスフレーズ>"));
 
       // 公開鍵にパスフレーズが無い場合
       //var authMethod = new PrivateKeyAuthenticationMethod("<リモートPCのユーザ名>",
                                                             new PrivateKeyFile(secretKeyPath, ""));
 
       // パスワード認証の場合
       //var authMethod = new PasswordAuthenticationMethod("<リモートPCのユーザ名>",
                                                           "<リモートPCのユーザ名のパスワード>")
 
       // 接続情報のインスタンス生成
       var connectionInfo = new ConnectionInfo("<リモートPCのIPアドレス または ホスト名>",
                                               <ト番号  : 22>,
                                               "<リモートPCのユーザ名>",
                                               authMethod);
 
       using (var client = new SftpClient(connectionInfo))
       {
          // SSH接続を行う
          client.Connect();
 
          // リモートPCのユーザディレクトリに移動
          client.ChangeDirectory("/home/username");
 
          // アップロードするファイルのパスを配列で指定
          string[] filePaths = { "/path/to/file1.txt", "/path/to/file2.jpg", "/path/to/file3.png" };
 
          foreach (string filePath in filePaths)
          {
             // ファイルを読み込み専用で開く
             using (var fs = File.OpenRead(filePath))
             {
                // ファイル名を取得
                string fileName = Path.GetFileName(filePath);
 
                // ファイルをアップロード(trueを指定すると上書き可能となる)
                client.UploadFile(fs, fileName, true);
             }
          }
 
          // SSH接続を切断
          client.Disconnect();
       }
    }
 }