java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
In above code why we need to set StrictHostKeyChecking value as no while connection to SFTP through JSch API?
You should NOT set it actually. You lose much of the SSH/SFTP security by doing to.
The option tells the JSch SSH/SFTP library not to verify public key of the SSH/SFTP server. You are vulnerable to man-in-the-middle attacks, if you do not verify the public key. Of course, unless you are connecting within a private trusted network (so you do not care for security/encryption).
Read about SSH/SFTP host keys:
https://winscp.net/eng/docs/ssh_verifying_the_host_key
StrictHostKeyChecking values: ask | yes | no
default: ask
If this property is set to yes, JSch will never automatically add host keys to the $HOME/.ssh/known_hosts file, and refuses to connect to hosts whose host key has changed. This property forces the user to manually add all new hosts.
If this property is set to no, JSch will automatically add new host keys to the user known hosts files.
If this property is set to ask, new host keys will be added to the user known host files only after the user has confirmed that is what they really want to do, and JSch will refuse to connect to hosts whose host key has changed.
Related
I'm running a java program where I transfer a file from one folder to another, using Java SFTP. The problem I'm having is that I'm getting the following error in my Java SFTP (using JSch) :
C:\Oracle\Middleware\Oracle_Home\oracle_common\jdk\bin\javaw.exe
-server -classpath C:\JDeveloper\mywork\Java_Hello_World.adf;C:\JDeveloper\mywork\Java_Hello_World\Client\classes;C:\Users\ADMIN\Downloads\jsch-0.1.53.jar
-Djavax.net.ssl.trustStore=C:\Users\IBM_AD~1\AppData\Local\Temp\trustStore5840796204189742395.jks
FileTransfer com.jcraft.jsch.JSchException: UnknownHostKey: 127.0.0.1.
RSA key fingerprint is a2:39:3f:44:88:e9:1f:d7:d1:71:f4:85:98:fb:90:dc
at com.jcraft.jsch.Session.checkHost(Session.java:797) at
com.jcraft.jsch.Session.connect(Session.java:342) at
com.jcraft.jsch.Session.connect(Session.java:183) at
FileTransfer.main(FileTransfer.java:33) Process exited with exit code
0.
The following is my code so far:
FileTransfer fileTransfer = new FileTransfer();
JSch jsch = new JSch();
try {
String host = "127.0.0.1";
int port = 22;
String user = "user";
Session session = jsch.getSession(user, host, port);
session = jsch.getSession("username", "127.0.0.1", 22);
session.connect(); // bug here , java.net.ConnectException
ChannelSftp sftp = null;
sftp = (ChannelSftp)session.openChannel("sftp") ; //channel;
//extra config code
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// end extra config code
sftp.rename("C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_1\\house.bmp", "C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_2\\house.bmp");
session.disconnect();
} catch (JSchException e) {
e.printStackTrace();
} catch (SftpException e) {
e.printStackTrace();
} //end-catch
My Cygwin is set up, and I checked (with netstat -a -b ) that it's running.
You are trying to skip a host key checking by setting StrictHostKeyChecking to no.
But you have to do that before the checking, i.e. before the session.connect().
Anyway, you should never do this, unless you do not care about security. The host key checking is there to protect you from man-in-the-middle attacks.
Instead, set up an expected host key to let JSch verify it.
For example:
Call JSch.setKnownHosts providing a path to a .ssh/known_hosts-like file.
To generate the .ssh/known_hosts-like file, you can use an ssh-keyscan command from OpenSSH. If you are connecting from a *nix server, you should have the command available, just run
ssh-keyscan example.com > known_hosts
It will have a format like:
example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0hVqZOvZ7yWgie9OHdTORJVI5fJJoH1yEGamAd5G3werH0z7e9ybtq1mGUeRkJtea7bzru0ISR0EZ9HIONoGYrDmI7S+BiwpDBUKjva4mAsvzzvsy6Ogy/apkxm6Kbcml8u4wjxaOw3NKzKqeBvR3pc+nQVA+SJUZq8D2XBRd4EDUFXeLzwqwen9G7gSLGB1hJkSuRtGRfOHbLUuCKNR8RV82i3JvlSnAwb3MwN0m3WGdlJA8J+5YAg4e6JgSKrsCObZK7W1R6iuyuH1zA+dtAHyDyYVHB4FnYZPL0hgz2PSb9c+iDEiFcT/lT4/dQ+kRW6DYn66lS8peS8zCJ9CSQ==
And reference the generated known_hosts file in your JSch code.
If you are on Windows, you can get a Windows build of ssh-keyscan from Win32-OpenSSH project or Git for Windows.
Call JSch.getHostKeyRepository().add() to provide the expected host key (e.g. hard-coded, as your other credentials).
See Creating JSch HostKey instance from a public key in .pub format.
jsch version : 0.1.55
my problem solved by running :
ssh-keyscan -t rsa <HOST_NAME> >> ~/.ssh/known_hosts
ssh-keyscan -t rsa <IP_ADDRESS_OF_HOST_NAME> >> ~/.ssh/known_hosts
**in my case jsch was looking for ip address in known_hosts file
jsch.setKnownHosts(System.getProperty("user.home")+"/.ssh/known_hosts");
Aside: by "Cygwin" I assume you mean sshd or sftpd, because Cygwin itself doesn't do SSH.
Anyway, if you want Jsch client to accept any key from the host, move the .setConfig calls that sets StrictHostKeyChecking no so it is before session.connect(). Alternatively you must provide access to a store containing the correct key(s) for your hosts(s) as #Martin explains -- and you should always do that when connecting to anything other than "localhost" or possibly a machine certain to be on the same, physically-secure network segment (such as a wired LAN hub within a single room).
This is how it looks like when I attempt to connect to the destination server from the jump server.
SSH Screen
Firstly, it prompts me for the username and password of the jump server.
Once logged in, I attempt to connect to the destination server. This is where that passphrase prompt comes in. All I need to do is hit enter when prompted for the passphrase and I will be prompted for the password.
Here's a snippet of my code:
Session jumpServerSession = jsch.getSession(jumpServerHostUsername, jumpServerHostName, 22);
jumpServerSession.setPassword(jumpServerPassword);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
jumpServerSession.setConfig(config);
jumpServerSession.connect();
int assinged_port = jumpServerSession.setPortForwardingL(0, targetServerHostname, 22);
System.out.println("portforwarding: "+
"localhost:"+assinged_port+" -> "+targetServerHostname+":"+22);
//Main server connection session started
Session targetServerSession = jsch.getSession("root", targetServerHostname, 22);
targetServerSession.setHostKeyAlias(targetServerHostname);
targetServerSession.setPassword(targetServerPassword);
targetServerSession.setIdentityRepository(null);
java.util.Properties config1 = new java.util.Properties();
config1.put("StrictHostKeyChecking", "no");
targetServerSession.setConfig(config1);
targetServerSession.connect();
Error Message
As you can see from the console output above, the connection gets timed out which is unsurprising since I couldn't find a way to just send that empty passphrase. I googled quite a bit and found a few articles (using Robot and setting config to "PreferredAuthentications", "publickey,keyboard-interactive,password"). They didn't work for me. Finally, I am unable to download the key from the jump server as well. Any help will be greatly appreciated! Thank you!
Edit: Apologies. I don't have enough reputation to post the images.
If the private key is not encrypted, there's nothing to be done in JSch. It will just use the key.
But I do not see you specifying your private key anywhere. If you expect the local JSch to somehow magically use the .ssh/id_da the key on the jump server, it won't. The JSch does not even know the jump server exists. You need the private key on the local machine and let JSch know about it.
I have an issue with my hostkey verification via JSch. I am using jsch 0.1.53, for my application, and the server I am connecting to is SouthRiverTech's Titan SFTP server.
I have tried generating a keypair with Puttygen, the Titan inbuilt key generator, and also with JSch's inbuilt libraries. The settings I used was RSA, 2048 bits.
The keys created by JSch's inbuilt libraries didn't seem to work. The keys generated by Titan and Puttygen were able to be used with winSCP, but kept giving me a "Reject Hostkey" error with JSch, which should be an issue with the known_hosts file. From what I have found, the known_hosts file should be the same as a public key file, but do tell me if I am wrong. I have set Titan's SFTP version to version 3.
I have the same keys set for the user profile in Titan to find out where the error lies, but to no avail. So far I have yet to find any answers online regarding hostkey issue between JSch and Titan server. This has been giving me a huge headache.
Thank you in advance for any answers you might have. I will try my best to post any information I might have missed out.
EDIT
Further debugging came up with JSchException: UnknownHostKey, followed by the RSA key fingerprint which is used by the server. My client key fingerprint and the server key fingerprint are the same, so why is this happening?
EDIT
Here is my Java code:
knownHostsFile = "D:/Keys/test.pub";
privateKey = "D:/Keys/test";
Session session = null;
Channel channel = null;
for(int i = 0; i < 3; i++) {
try {
logger.debug("Starting Upload");
JSch ssh=new JSch();
logger.debug("setting hosts - public key");
ssh.setKnownHosts(knownHostsFile);
logger.debug("Known hosts set as "+knownHostsFile);
logger.debug("Setting identity - private key");
ssh.addIdentity(privateKey);
logger.debug("identity set");
try {
int hostSFTPPort = Integer.parseInt(sftpPort);
if (!hostUserName.equalsIgnoreCase("no")
&& !hostPassword.equalsIgnoreCase("no")
&& !hostAddress.equalsIgnoreCase("no")) {
session=ssh.getSession(hostUserName,hostAddress,hostSFTPPort);
session.setPassword(hostPassword);
}
} catch (NumberFormatException ef){
logger.debug(ef);
}
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "yes");
config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
session.setConfig(config);
logger.debug("Establishing connection...");
session.connect(120000);
logger.debug("Connection established.");
logger.debug("Creating SFTP Channel.");
channel=session.openChannel("sftp");
logger.debug("Channel assigned. Connecting channel...");
channel.connect(120000);
logger.debug("SFTP Channel created.");
ChannelSftp sftp = (ChannelSftp) channel;
logger.debug("connection:"+sftp.isConnected());
if(sftp.isConnected()) {
result=Constants.CONNECTION_ONLINE;
}
session.disconnect();
channel.disconnect();
break;
} catch (JSchException e) {
logger.debug(e);
logger.debug(session.getHost());
logger.debug(session.getHostKey());
logger.debug("Continuing next loop......");
throw new JSchException("Session.connect failed",e);
} catch (Exception ex) {
logger.debug(ex);
logger.debug("Continuing next loop......");
continue;
}
}
Here is a picture of the Server admin console
Here are the keys I'm having trouble with:
This one does not seem to work with winSCP, and was created in a Linux environment
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA4R+w9rGUsBNJGZxAdnbnA7FMfGGhx3YaLYZtKf9wzKm8NkZeYIuh1fJ6ViX6RmdO55QxQ3PmBIg8QdhQ8m6SizEt9OGeXU2AnEbX/sbj54oHmiFsv24eDFzr7nrDKnrcllByob3LqjeOy5zg27kJt860oh6BAJfimdqVtETSXR1JHfqUIqGxIqsvyKEotX8gjoGkgsW653f18dW5PJKSEvrq6k1SL0bfgSAA0rN4nUq3JzDvowg5ijkOl91/lj8+FEQ7SjWmguTSx5BoI/CTxatCwNZSdzNED/u5A8I3716JuY7MEiTciPdzspGAXS2mHOtsDPkT7z6jvKQ6hWWv/w== test1#10.70.149.178
This one works with winSCP, and was created in a Windows environment
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "test"
AAAAB3NzaC1yc2EAAAABJQAAAQEA9a1nnbl/DV2Zo7s1IUifeC5suRmdO2ikSb0ToteO9uvA
gg0zYKA1iH52ysC+4Ni86Ceal4oWGl1dXZRKOaWNH6175uDTI1aBfPBvOddBheTeSQAWOkaM
eL5PDDabLkaKZ1GrtbTeEFOD/Kj/dVREhT5/OcEdFmCbHK6+vr2klrtH2xOd/Qeb89BzDFaj
weNER3fFnHVqy5/Nugo3n7CsiBxuK8KOVN4WpDHzrVe/tjAfVZyH8l4XHlR7bWA5rlAGwt0Y
HILQ+lT1PRmi5PiDq7WuP7NF3QhWjG/D1u/5PC/DzxjTOxwwmXfYj2T2OkE/2/tHSdU4geYr
+1ivdASJ5w==
---- END SSH2 PUBLIC KEY ----
You are confusing an account key pair with a host key (pair).
The JSchException "reject HostKey: ..." indicates that the server's public key (aka host key) differs from the public key known by your code or cached in the known_hosts file.
The server's host key is typically not generated by PuTTYgen (though it might be possible) and definitely has nothing to do with WinSCP. In PuTTYgen you typically generate an account key pair (which you can then use e.g. in WinSCP).
For details, see my article Understanding SSH key pairs.
The account key pair and host key pair have nothing to do with each other. Whatever you use for the account key, it won't make JSch accept the server's host key. Just forget this idea. It's completely wrong.
You have to provide the correct host key in the known_hosts file (or other implementation of the JSch HostKeyRepository interface). You cannot use a .pub file for the known_hosts file. The known_hosts file has a set format like:
IP_address ssh-rsa public_key
You can also use KnownHosts.add to set the expected hostkey on runtime.
I'm using Jsch for executing ssh commands.
When I pass private key it works well, but I need it to work without private key passing (it was already copied there).
So in console I can ssh to this server without anything. But Jsch throws Auth Fail. How can I do it ?
Session session = jSch.getSession(server);
session.setConfig("StrictHostKeyChecking", "no");
session.setConfig("UserKnownHostsFile", "/dev/null");
session.connect(connectTimeout);
By design, you always need to have the private key to prove you are who you say you are. Your private key is never "already copied there." If you are successfully connecting with ssh in a shell "without anything" it is certainly because your ssh is configured to find the private key and it is doing so successfully.
I need to be able to ssh from a Java program into a remote server, and from there SSH to another server. I have credentials for both servers on my client.
The commands will be passed automatically from within the app as regular strings (no user input). I need to be able to run those custom commands on the second server and be able to decide what commands to issue during runtime, based on the output and some simple logic.
Can I use JSch to do that and if yes, where should I start look into? (Examples, info)
=============================================================
ADDED:
Exception in thread "main" com.jcraft.jsch.JSchException:
UnknownHostKey: host.net. RSA key fingerprint is 'blahblahblah'
as till now, I am solving this problem by modifying the known_hosts file and adding host manually in there.
Can I bypass this little problem by settings an option somewhere telling the JSch to press YES automatically when this YES-NO question is asked?
To connect to a second server behind a firewall, there are in principle two options.
The naive one would be to call ssh on the first server (from an exec channel), indicating the right server. This would need agent forwarding with JSch, and also doesn't provide the JSch API to access the second server, only the ssh command line.
The better one would be to use the connection to the first server to build up a TCP Tunnel, and use this tunnel to connect to the second server. The JSch Wiki contains a ProxySSH class (together with some example code) which allows to use a JSch session as a tunnel for a second JSch session. (Disclaimer: This class was written mainly by me, with some support from the JSch author.)
When you have your connection to the second server, use either a shell channel or a series of exec channels to execute your commands. (See Shell, Exec or Subsystem Channel in the JSch Wiki for an overview, and the Javadocs for details.)
For your unknown-host-key problem:
The secure version would be to collect all host keys (in a secure way) before and put them in the known_hosts file. (If you simply trust the key which is presented to you, you are vulnerable to a man-in-the-middle attack. If these are of no concern in your network, since it is physically secured, good for you.)
The convenient version is setting the configuration option StrictHostKeyChecking to no - this will add unknown host keys to the host keys file:
JSch.setConfig("StrictHostKeyChecking", "no");
(You can also set it individually on the sessions, if you only want to set it for the proxied sessions and not for the tunnel session. Or override it for the tunnel session with yesor ask - there the MITM danger might be greater.)
A middle way would be to enable actually asking the user (which then should compare the fingerprints to some list) - for this, implement the UserInfo interface and provide the object to the session. (The JSch Wiki contains an example implementation using Swing JOptionPanes, which you can simply use if your client program runs on a system with GUI.)
For the saving of accepted host keys to work, you must use the JSch.setKnownHosts method with a file name argument, not the one with an InputStream argument - else your accepting will have to be repeated for each restart of your client.
Use an SSH tunnel, aka local port forwarding, to open an SSH/SFTP connection to B via A.
Session sessionA = jsch.getSession("usernameA", "hostA");
// ...
sessionA.connect();
int forwardedPort = sessionA.setPortForwardingL(0, "hostB", 22);
Session sessionB = jsch.getSession("usernameB", "localhost", forwardedPort);
// ...
sessionB.connect();
// Use sessionB here for shell/exec/sftp
You may need to deal with UnknownHostKey exception.
This can help anyone. Works fine:
public static void sesionA(){
try {
Session sessionA = jSch.getSession(username, hostA);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionA.setConfig(config);
sessionA.setPassword(passwordA);
sessionA.connect();
if(sessionA.isConnected()) {
System.out.println("Connected host A!");
forwardedPort = 2222;
sessionA.setPortForwardingL(forwardedPort, hostB, 22);
}
} catch (JSchException e) {
e.printStackTrace();
}
}
public static void sesionB(){
try {
Session sessionB = jSch.getSession(username, "localhost", forwardedPort);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
sessionB.setConfig(config);
sessionB.setPassword(passwordB);
sessionB.connect();
if(sessionB.isConnected()) {
System.out.println("Connected host B!");
}
}
}