none
SFTPでのファイルアップロード方法 RRS feed

  • 質問

  • 先方からSFTPでアップロードしてほしいとの依頼がありました。

    とあるサイトからFTPでのアップロード方法を調査し、下記のスクリプトに
    $ftpReq.EnableSsl = $true
    と言う一行を追加し、実行したところし

    「検証プロシージャによると、リモート証明書は無効です。」

    と言うエラーが発生しました。

    SFTPでファイルをアップロードするにはFTPでのアップロードに加え、どのような情報が必要なのでしょうか。
    先方からはアドレス、ID、パスワードに加え、ポートを990でと言う指示もあります。
    ポートはどのように設定すれば良いのでしょうか。

    ===========コード==============

    $ftpFileName = "ftp://address/" + $fileName
    $ftpReq = [System.Net.FtpWebRequest]::Create($ftpFileName)
    $ftpReq.Credentials = New-Object System.Net.NetworkCredential("id","pass")
    $ftpReq.Method = [System.Net.WebRequestMethods+ftp]::UploadFile
    $ftpReq.KeepAlive = $true
    $ftpReq.UseBinary = $true
    $ftpReq.EnableSsl = $true
    $ftpReq.UsePassive = $false
    $ftpReq.TimeOut = 10000
    $stream = $ftpReq.GetRequestStream()
    $fileStream  = New-Object System.IO.FileStream($fileName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)

    2014年7月25日 10:14

回答

  • FTPサーバー側で自己署名証明書を使用しているのではないでしょうか?

    その証明書の妥当性をクライアントが検証できないため、エラーになっているものと思われます。

    もしクライアント側にサーバーで使用している自己署名証明書をインストールする権限があるのなら、実施すればOKです。

    仮にできない場合でも、クライアントでの妥当性検証方法をコードで指定することで、この問題に対処できます。

    具体的には、以下のコードをスクリプト先頭に挿入しておくことになります。

    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    このコードでは{}の中身のスクリプトが、証明書の妥当性検証を行うときに実行されるようになりますが、単に$trueを返すようにしておけば、すべての検証がOK(証明書は妥当)ということになります。本来であれば、妥当性を検証するコードをちゃんと書くべきですが、他にデータのセキュアなリモートダウンロードを行うコードがスクリプト中に含まれていないならば、これでも一応用は足りるかと思います。

    なお、より詳細な話をすると、上記のコードはスクリプトブロックからデリゲートへの型変換機能を使っています。この機能はたしかPowerShell 3.0からのものなので、2.0以下の場合はもうちょっと複雑になると思います。その場合はまた聞いてください。

    • 回答としてマーク UltraKatan 2014年7月28日 10:48
    2014年7月25日 11:24
    モデレータ

すべての返信

  • FTPサーバー側で自己署名証明書を使用しているのではないでしょうか?

    その証明書の妥当性をクライアントが検証できないため、エラーになっているものと思われます。

    もしクライアント側にサーバーで使用している自己署名証明書をインストールする権限があるのなら、実施すればOKです。

    仮にできない場合でも、クライアントでの妥当性検証方法をコードで指定することで、この問題に対処できます。

    具体的には、以下のコードをスクリプト先頭に挿入しておくことになります。

    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    このコードでは{}の中身のスクリプトが、証明書の妥当性検証を行うときに実行されるようになりますが、単に$trueを返すようにしておけば、すべての検証がOK(証明書は妥当)ということになります。本来であれば、妥当性を検証するコードをちゃんと書くべきですが、他にデータのセキュアなリモートダウンロードを行うコードがスクリプト中に含まれていないならば、これでも一応用は足りるかと思います。

    なお、より詳細な話をすると、上記のコードはスクリプトブロックからデリゲートへの型変換機能を使っています。この機能はたしかPowerShell 3.0からのものなので、2.0以下の場合はもうちょっと複雑になると思います。その場合はまた聞いてください。

    • 回答としてマーク UltraKatan 2014年7月28日 10:48
    2014年7月25日 11:24
    モデレータ
  • あとポート番号指定ですが、

    $ftpFileName = "ftp://address:990/" + $fileName

    のようにURIに指定するだけでいけるんじゃないでしょうか。

    • 回答としてマーク UltraKatan 2014年7月28日 10:48
    • 回答としてマークされていない UltraKatan 2014年7月28日 10:48
    2014年7月25日 11:32
    モデレータ
  • 余談ですが…

    先方の指定したsftpの正式名称はSSH File Transfer ProtocolでSSHを使うもので、.NET Frameworkでは実現できません。sftpとは別にftpsというものがありこちらはFile Transfer Protocol over SSL/TLSです。こちらは.NET Frameworkも対応しています。ポート番号は990が一般的なので、たぶん先方の指示が間違っているのだと思います。

    また今回のエラーとは別ですがUsePassiveを$trueにした方がつながりやすいです。

    • 回答としてマーク UltraKatan 2014年7月28日 10:48
    • 回答としてマークされていない UltraKatan 2014年7月28日 10:49
    2014年7月25日 12:34
  • [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    $ftpReq.EnableSsl = $true

    のコンボでいけました。

    どうやら、EnableSslをTrueにするとポートが990になるようです。

    "ftp://address:990/" + $fileName

    ではエラーになってしまいました。

    2014年7月28日 10:50
  • 先方に確認したところ、SFTPではなくFTPSの誤りでした。

    無事解決致しました。

    ありがとうございます。

    2014年7月28日 10:51
  • 追記、

    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    ですが、Server2003上で動作しました。

    2.0でも動作可能なのかも知れません。

    2014年7月29日 0:14