I have a C# .NET project, where am trying to open an SFTP connection to a server and put a file to the server.
I have SFTP hostname, username and key file (.pem file).
I do not have a password here.
Please help me with something to use SFTP in C# and .Net.
Probably every SFTP/SSH library supports public key authentication.
For example:
SSH.NET (NuGet package):
var privateKey = new PrivateKeyFile(#"C:\some\path\key.pem");
var client = new SftpClient("example.com", "username", new[] { privateKey });
client.Connect();
If the private key is encrypted:
var privateKey = new PrivateKeyFile(#"C:\some\path\key.pem", "passphrase");
WinSCP .NET assembly (NuGet package):
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "example.com",
UserName = "username",
SshHostKeyFingerprint = "ssh-rsa 2048 ...=",
SshPrivateKeyPath = #"C:\some\path\key.ppk",
};
using (Session session = new Session())
{
session.Open(sessionOptions);
// Your code
}
WinSCP needs the key converted to PPK format (You can use WinSCP GUI for that, or PuTTYgen). Also note that WinSCP verifies the SSH host key (SshHostKeyFingerprint). SSH.NET fails to do that by default, what is a security flaw.
If the private key is encrypted, add PrivateKeyPassphrase or SecurePrivateKeyPassphrase.
WinSCP GUI can generate a code template for you.
(I'm the author of the library)
I ran into this same issue. The code provided by Martin certainly helped me but, it was missing a couple settings for my needs.
I needed to add a Port Number and a Pass Phrase to fully automate my solution. So code ends up like:
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
PortNumber = port,
HostName = host,
UserName = username,
PrivateKeyPassphrase = passphrase,
SshHostKeyFingerprint = fingerprint,
SshPrivateKeyPath = privatekeyfile
};
Related
I'm writing an OPC UA Client in C# using OPC Foundation NuGet package.
I can succesfully connect to server, read and write variables and create subscriptions and monitored items.
Since I'd like to use this code in production environments, I need to use secure connection (username / password policy instead of anonymous connection).
This is how I'm doing it:
bool security = true; // Set here security enabled
Session session; // OPC UA Session
// 1. Generate client application
ApplicationInstance application = new() { ApplicationType = ApplicationType.Client };
// 2. Load application configuration
ClientConfiguration clientConfiguration = new() { DefaultSessionTimeout = _timeout };
ApplicationConfiguration configuration = new() { ApplicationName = "OPC Foundation SDK Personal Implementation", ClientConfiguration = clientConfiguration, ApplicationUri = "urn:OPC Foundation SDK Personal Implementation" };
application.ApplicationConfiguration = configuration;
// 3. Get the endpoint by connecting to server's discovery endpoint
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint($"opc.tcp://{Target}", security);
// 4. Get server certificate
var rawCertificate = endpointDescription.ServerCertificate;
CertificateIdentifier serverCertificate = new(rawCertificate);
// 5. Add server certificate to trusted peers and trusted issuers
configuration.SecurityConfiguration.TrustedPeerCertificates.TrustedCertificates.Add(serverCertificate);
configuration.SecurityConfiguration.TrustedIssuerCertificates.TrustedCertificates.Add(serverCertificate);
// 6. Create application instance certificate
var appCertificate = new X509Certificate2("TestCertificate.der", "");
configuration.SecurityConfiguration.AddAppCertToTrustedStore = true;
configuration.SecurityConfiguration.ApplicationCertificate = new(appCertificate);
// Validate the configuration
configuration.Validate(ApplicationType.Client);
var result = application.CheckApplicationInstanceCertificate(true, CertificateFactory.DefaultKeySize);
// 7. Setup endpoint
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
ConfiguredEndpoint endpoint = new(null, endpointDescription, endpointConfiguration);
// 8. Create session
if (security)
session = Session.Create(configuration, endpoint, false, false, configuration.ApplicationName, (uint)configuration.ClientConfiguration.DefaultSessionTimeout, new UserIdentity("****", "****"), null).Result; // Username and password
else
session = Session.Create(configuration, endpoint, false, false, configuration.ApplicationName, (uint)configuration.ClientConfiguration.DefaultSessionTimeout, new UserIdentity(), null).Result; // Anonymous login to OPC UA server
If security is set to true, I get error "certificate chain validation incomplete". This is referred at my application instance certificate because without security the session is created successfully (so I'm sure the server certificate is being accepted).
The certificate I'm using is self-signed and it is generated with the following code:
public static void CreateApplicationCertificate(string certFilename, string keyFilename)
{
const string CRT_HEADER = "-----BEGIN CERTIFICATE-----\n";
const string CRT_FOOTER = "\n-----END CERTIFICATE-----";
const string KEY_HEADER = "-----BEGIN RSA PRIVATE KEY-----\n";
const string KEY_FOOTER = "\n-----END RSA PRIVATE KEY-----";
using var rsa = RSA.Create();
var certRequest = new CertificateRequest("cn=TestCertificate", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// This is a test and the certificate is being regenerated every time I run the code, so one day is enough.
var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));
// Export the private key
var privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks);
File.WriteAllText(keyFilename + ".pem", KEY_HEADER + privateKey + KEY_FOOTER);
// Export the certificate
var exportData = certificate.Export(X509ContentType.Cert);
var crt = Convert.ToBase64String(exportData, Base64FormattingOptions.InsertLineBreaks);
File.WriteAllText(certFilename + ".der", CRT_HEADER + crt + CRT_FOOTER);
}
I added this line of code
configuration.SecurityConfiguration.AddAppCertToTrustedStore = true;
but nothing changed.
Any help is really appreciated.
I'm trying to upload file to FileZilla server through ftps by protocol TLS. On the server port 20 and 21 is closed. The only way how I managed to connect to server is by using FluentFTP but I couldn't upload file because of some FileZilla server bug.
https://github.com/robinrodricks/FluentFTP/issues/335
https://forum.filezilla-project.org/viewtopic.php?t=51601
public static void UploadTest(
string pathUploadFile, string addressIP, int port, string location,
string userName, string password)
{
FtpClient ftp;
Console.WriteLine("Configuring FTP to Connect to {0}", addressIP);
ftp = new FtpClient(addressIP, port, new NetworkCredential(userName, password));
ftp.ConnectTimeout = 600000;
ftp.ReadTimeout = 60000;
ftp.EncryptionMode = FtpEncryptionMode.Implicit;
ftp.SslProtocols = SslProtocols.Default | SslProtocols.Tls11 | SslProtocols.Tls12;
ftp.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
ftp.Connect();
// upload a file
ftp.UploadFile(pathUploadFile, location);
Console.WriteLine("Connected to {0}", addressIP);
ftp.Disconnect();
void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
{
// add logic to test if certificate is valid here
e.Accept = true;
}
}
Is there any way around without a violating security level? If not is there any other free library which support uploading files with TLS/SSL? I also tried this but it didn't work.
https://learn.microsoft.com/en-us/dotnet/api/system.net.ftpwebrequest.enablessl
Thanks.
You can use WinSCP .NET assembly.
It supports implicit TLS (port 990). And uses OpenSSL TLS implementation (not .NET Framework), so it should not have the problem that FluentFTP has. It definitely works for me against FileZilla FTP server, even with session resumption requirement turned on.
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "ftp.example.com",
UserName = "username",
Password = "password",
FtpSecure = FtpSecure.Implicit,
TlsHostCertificateFingerprint = "xx:xx:xx:...",
};
using (Session session = new Session())
{
session.Open(sessionOptions);
session.PutFiles(localPath, remotePath).Check();
}
(I'm the author of WinSCP)
For more references about the problem, see also Can connect to FTP using FileZilla or WinSCP, but not with FtpWebRequest or FluentFTP.
Our IT department gave me credentials for an FTPS, which I can access using FileZilla
But I also need to access the FTPS using an application I am working on to automate the process. The information provided to me was,
That this is an FTP over TLS/SSL
IP: xxx.xxx.xx.xx
Port: 990 <-- suggesting its an implicit encryption
UserName: username.ftp
Password: password123
After reading some posts on WinSCP on stack and their documentation, I still can't access the ftps using my application. My code so far..
SessionOptions sessionOp = new SessionOptions()
{
FtpSecure = FtpSecure.Implicit,
Protocol = Protocol.Ftp,
HostName = IP,
UserName = userName,
Password = password,
};
sessionOp.AddRawSettings("ProxyMethod", "3");
sessionOp.AddRawSettings("ProxyPort", "990");
using (Session session = new Session())
{
session.Open(sessionOp);
var list = session.ListDirectory(dir);
Console.WriteLine(list);
}
The error I get is, "Failed to Connect" from WinSCP
How can I access this FTPS?
What you did is configuring the HTTP Proxy port to 990. Instead you should configure the FTPS port.
SessionOptions sessionOp = new SessionOptions()
{
FtpSecure = FtpSecure.Implicit,
Protocol = Protocol.Ftp,
HostName = IP,
UserName = userName,
Password = password,
PortNumber = 990
};
and remove the lines
sessionOp.AddRawSettings("ProxyMethod", "3");
sessionOp.AddRawSettings("ProxyPort", "990");
Also, I suggest using the WinSCP GUI to try this instead of FileZilla, considering that the library is related to the GUI.
I'm trying to connect to a server with a SFTP connection, but I'm trying to authenticate with SSH fingerprint, if this is not correct, then should attempt with the SFTP password.
The issue that I'm having is that need both of them to access to the server, that should be different, if is not the SSH fingerprint, then try with the password, but is not working.
There is a way to validate first the fingerprint and if is not correct, validate the user password?
This is what I have:
public string FilesSFTP_FTP()
{
TransferOptions TransferOption = new TransferOptions();
TransferOperationResult TransferResult;
SessionOptions sessionoptions = new SessionOptions();
Session session = new Session();
if (DataFile.sTransportType == "S")
{
sessionoptions.Protocol = Protocol.Sftp;
sessionoptions.PortNumber = 22;
sessionoptions.SshHostKeyFingerprint = DataFile.sFingerPrint;
}
else if (DataFile.sTransportType == "F")
{
sessionoptions.Protocol = Protocol.Ftp;
sessionoptions.PortNumber = 21;
}
sessionoptions.HostName = DataFile.sIPAddress;
sessionoptions.UserName = DataFile.sUserID;
sessionoptions.Password = DataFile.sPassword;
TransferOption.TransferMode = TransferMode.Binary;
TransferOption.PreserveTimestamp = false;
TransferOption.ResumeSupport.State = TransferResumeSupportState.Off;
session.Open(sessionoptions);
}
There is another property that it need to be set?
You cannot "authenticate with SSH fingerprint".
The SessionOptions.SshHostKeyFingerprint is to verify the server's host key. Not to authenticate the user.
To authenticate the user, you need to use the SessionOptions.SshPrivateKeyPath.
See Understanding SSH key pairs to learn the difference.
As for your question. You can set both the SessionOptions.SshPrivateKeyPath and the SessionOptions.Password. WinSCP will first try the private key, and only if that fails, it will fall back to the password. (Or it will use both, is the server requires that)
I am trying to impersonate remote admin user so that i can perform modifications on the files present on remote Linux machine. But i get error message as Access to the path is denied.
However this thing manually i am able to do via putty using command :
sudo -S -u wtsnqa rm /path-to-file/
Any help is worth appreciable.
My code :
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = "sj1slm612",
UserName = "userid",
Password = "password",
SshHostKeyFingerprint = "ssh-rsa 2048 fa:e9:58:24:1b:41:a3:15:63:0d:c0:72:41:5d:51:7a"
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Performing removing files from remote server via impersonation.......
AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
using (WindowsIdentity Authorized_user = new WindowsIdentity("wtsnqa"))
{
using (WindowsImpersonationContext context = Authorized_user.Impersonate())
{
File.Delete(#"\\sj1slm612\apps\instances\express_13000\configuration\standalone-full.xml");
File.Delete(#"\\sj1slm612\apps\instances\query_13100\configuration\standalone-full.xml");
File.Delete(#"\\sj1slm612\apps\instances\wppapi_13200\configuration\standalone-full.xml");
File.Delete(#"\\sj1slm612\apps\instances\wppgui_13300\configuration\standalone-full.xml");
Console.WriteLine("All config files removed from sj1slm612");
Console.ReadLine();
context.Undo();
}