Java SFTP 服务器库? [关闭]
Posted
技术标签:
【中文标题】Java SFTP 服务器库? [关闭]【英文标题】:Java SFTP server library? [closed] 【发布时间】:2011-03-05 19:44:27 【问题描述】:是否有可用于实现SFTP 服务器的 Java 库?
我正在尝试通过 SFTP 接收文件,但我似乎找不到任何 SFTP 服务器的实现。我找到了 FTP/SFTP/FTPS client 库和 FTP/FTPS 服务器库,但没有找到 SFTP 服务器。
为了澄清,我正在尝试通过 SFTP接收文件。不是从我的应用程序“获取”或“放置”文件到另一个现有服务器。
现在我的应用程序让用户连接到本地 linux SFTP 服务器,删除文件,然后我的应用程序轮询目录,但我觉得这是一个糟糕的实现;我讨厌“轮询”目录的想法,但不幸的是他们必须使用 SFTP。有什么建议吗?
【问题讨论】:
【参考方案1】:如何使用Apache Mina SSHD 设置 SFTP 服务器:
public void setupSftpServer()
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(22);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
userAuthFactories.add(new UserAuthNone.Factory());
sshd.setUserAuthFactories(userAuthFactories);
sshd.setCommandFactory(new ScpCommandFactory());
List<NamedFactory<Command>> namedFactoryList = new ArrayList<NamedFactory<Command>>();
namedFactoryList.add(new SftpSubsystem.Factory());
sshd.setSubsystemFactories(namedFactoryList);
try
sshd.start();
catch (Exception e)
e.printStackTrace();
仅此而已。
【讨论】:
这会创建一个大多数现代客户端拒绝连接的 SSH 服务器 :-( 请参阅 ***.com/questions/33690689/…【参考方案2】:请注意,SFTP 不是基于 SSL 的 FTP,也不是基于 SSH 的 FTP。 SFTP 服务器支持需要在 Java 中实现 SSHD。最好的选择是 Apache SSHD,
http://mina.apache.org/sshd-project/
我从未使用过 SFTP,但我听说它很基本但很实用。
【讨论】:
好点。术语完全令人困惑。很多人认为 SFTP 是“安全 FTP”,或者是通过 SSL 或 SSH 或其他方式运行的 FTP 版本(但事实并非如此)。我希望他们把它叫做完全不同的东西。 链接失效了 而基于 SSL 的 FTP 被称为 FTPS,见de.wikipedia.org/wiki/FTP_%C3%BCber_SSL Mina SSHD 似乎已移至github.com/apache/mina-sshd【参考方案3】:我尝试使用上述方法在 Windows 上执行 MINA 0.10.1 并修复了一些问题,另外我需要更好的身份验证和 PK 支持(仍然不推荐用于生产):
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;
import java.math.BigInteger;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.KeyFactory;
import java.security.spec.KeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.SshServer;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthPassword;
import org.apache.sshd.server.auth.UserAuthPublicKey;
import org.apache.sshd.common.KeyExchange;
//import org.apache.sshd.server.kex.DHGEX;
//import org.apache.sshd.server.kex.DHGEX256;
import org.apache.sshd.server.kex.ECDHP256;
import org.apache.sshd.server.kex.ECDHP384;
import org.apache.sshd.server.kex.ECDHP521;
import org.apache.sshd.server.kex.DHG1;
import org.apache.mina.util.Base64;
/*
javac -classpath .;lib/sshd-core-0.10.1.jar;lib/mina-core-2.0.7.jar;lib/waffle-jna.jar;lib/guava-13.0.1.jar;lib/jna-platform-4.0.0.jar;lib/jna-4.0.0.jar SFTPServer.java
java -classpath .;lib/sshd-core-0.10.1.jar;lib/slf4j-simple-1.7.6.jar;lib/slf4j-api-1.6.6.jar;lib/mina-core-2.0.7.jar;lib/waffle-jna.jar;lib/guava-13.0.1.jar;lib/jna-platform-4.0.0.jar;lib/jna-4.0.0.jar SFTPServer
*/
public class SFTPServer
public void setupSftpServer() throws Exception
class AuthorizedKeyEntry
private String keyType;
private String pubKey;
private byte[] bytes;
private int pos;
private PublicKey key = null;
private int decodeInt()
return ((bytes[pos++] & 0xFF) << 24) | ((bytes[pos++] & 0xFF) << 16)
| ((bytes[pos++] & 0xFF) << 8) | (bytes[pos++] & 0xFF);
private BigInteger decodeBigInt()
int len = decodeInt();
byte[] bigIntBytes = new byte[len];
System.arraycopy(bytes, pos, bigIntBytes, 0, len);
pos += len;
return new BigInteger(bigIntBytes);
private void decodeType()
int len = decodeInt();
keyType = new String(bytes, pos, len);
pos += len;
public PublicKey getPubKey()
return key;
public void setPubKey(PublicKey key) throws Exception
this.key = key;
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
if (key instanceof RSAPublicKey)
keyType = "ssh-rsa";
dos.writeInt(keyType.getBytes().length);
dos.write(keyType.getBytes());
RSAPublicKey rsakey = (RSAPublicKey)key;
BigInteger e = rsakey.getPublicExponent();
dos.writeInt(e.toByteArray().length);
dos.write(e.toByteArray());
BigInteger m = rsakey.getModulus();
dos.writeInt(m.toByteArray().length);
dos.write(m.toByteArray());
else if (key instanceof DSAPublicKey)
keyType = "ssh-dss";
dos.writeInt(keyType.getBytes().length);
dos.write(keyType.getBytes());
DSAPublicKey dsskey = (DSAPublicKey)key;
BigInteger p = dsskey.getParams().getP();
dos.writeInt(p.toByteArray().length);
dos.write(p.toByteArray());
BigInteger q = dsskey.getParams().getQ();
dos.writeInt(q.toByteArray().length);
dos.write(q.toByteArray());
BigInteger g = dsskey.getParams().getG();
dos.writeInt(g.toByteArray().length);
dos.write(g.toByteArray());
BigInteger y = dsskey.getY();
dos.writeInt(y.toByteArray().length);
dos.write(y.toByteArray());
else
throw new IllegalArgumentException("unknown key encoding " + key.getAlgorithm());
bytes = byteOs.toByteArray();
this.pubKey = new String(Base64.encodeBase64(bytes));
public void setPubKey(String pubKey) throws Exception
this.pubKey = pubKey;
bytes = Base64.decodeBase64(pubKey.getBytes());
if (bytes == null)
return;
decodeType();
if (keyType.equals("ssh-rsa"))
BigInteger e = decodeBigInt();
BigInteger m = decodeBigInt();
KeySpec spec = new RSAPublicKeySpec(m, e);
key = KeyFactory.getInstance("RSA").generatePublic(spec);
else if (keyType.equals("ssh-dss"))
BigInteger p = decodeBigInt();
BigInteger q = decodeBigInt();
BigInteger g = decodeBigInt();
BigInteger y = decodeBigInt();
KeySpec spec = new DSAPublicKeySpec(y, p, q, g);
key = KeyFactory.getInstance("DSA").generatePublic(spec);
else
throw new IllegalArgumentException("unknown type " + keyType);
final SshServer sshd = SshServer.setUpDefaultServer();
final Map<ServerSession, PublicKey> sessionKeys = new HashMap();
class AuthorizedKeys extends HashMap<String,AuthorizedKeyEntry>
private File file;
public void load(File file) throws Exception
this.file = file;
Scanner scanner = new Scanner(file).useDelimiter("\n");
while (scanner.hasNext())
decodePublicKey(scanner.next());
scanner.close();
public void save() throws Exception
PrintWriter w = new PrintWriter(file);
for (String username : keySet())
AuthorizedKeyEntry entry = get(username);
w.print(entry.keyType + " " + entry.pubKey + " " + username + "\n");
w.close();
public void put(String username, PublicKey key)
AuthorizedKeyEntry entry = new AuthorizedKeyEntry();
try
entry.setPubKey(key);
catch (Exception e)
e.printStackTrace();
super.put(username,entry);
private void decodePublicKey(String keyLine) throws Exception
AuthorizedKeyEntry entry = new AuthorizedKeyEntry();
String[] toks = keyLine.split(" ");
String username = toks[toks.length-1];
for (String part : toks)
if (part.startsWith("AAAA"))
entry.setPubKey(part);
//bytes = Base64.decodeBase64(part.getBytes());
break;
super.put(username,entry);
;
final AuthorizedKeys authenticUserKeys = new AuthorizedKeys(); // load authorized_keys
File file = new File("authorized_keys");
file.createNewFile(); // create if not exists
authenticUserKeys.load(file);
sshd.setPort(22);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("key.ser"));
sshd.setShellFactory(new ProcessShellFactory(new String[] "cmd.exe "));
sshd.setPasswordAuthenticator(new PasswordAuthenticator()
public boolean authenticate(String username, String password, ServerSession session)
boolean authentic = false;
try
new waffle.windows.auth.impl.WindowsAuthProviderImpl().logonUser(username,password);
authentic = true;
//authentic = username != null && username.equals(password+password); // obsecurity :)
if (authentic)
PublicKey sessionKey = sessionKeys.get(session);
if (sessionKey != null)
authenticUserKeys.put(username, sessionKey); //save entry to authorized_keys
catch (Exception e)
System.err.println(e);
return authentic;
);
sshd.setPublickeyAuthenticator(new PublickeyAuthenticator()
public boolean authenticate(String username, PublicKey key, ServerSession session)
sessionKeys.put(session,key);
return key.equals(authenticUserKeys.get(username).getPubKey());
);
sshd.setUserAuthFactories(Arrays.<NamedFactory<UserAuth>>asList(
new UserAuthPublicKey.Factory()
,new UserAuthPassword.Factory()));
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(
new SftpSubsystem.Factory()));
//workaround for apache sshd 10.0+ (putty)
sshd.setKeyExchangeFactories(Arrays.<NamedFactory<KeyExchange>>asList(
//new DHGEX256.Factory()
//,new DHGEX.Factory()
new ECDHP256.Factory()
,new ECDHP384.Factory()
,new ECDHP521.Factory()
,new DHG1.Factory()));
Runtime.getRuntime().addShutdownHook(new Thread()
public void run()
try
authenticUserKeys.save();
System.out.println("Stopping");
sshd.stop();
catch (Exception e)
e.printStackTrace();
);
System.out.println("Starting");
try
sshd.start();
Thread.sleep(Long.MAX_VALUE);
catch (Exception e)
e.printStackTrace();
static public void main(String[] args) throws Exception
new SFTPServer().setupSftpServer();
【讨论】:
【参考方案4】:看看SSHTools (j2ssh)。它包括客户端和服务器。
但是轮询目录并不是一个坏主意——它可能比使用 j2ssh 设置您自己的 SFTP 服务器可靠得多。我已经记不清我遇到的执行这种轮询的应用程序的数量了,而且它通常工作得很好。
【讨论】:
我不知道它过去是否这样做,但它现在似乎不提供(n 开源)服务器。也许它已被转移到他们的商业产品中。【参考方案5】:仅出于完整性考虑 - 我们维护的 SecureBlackbox 库提供了用于在 Java(包括 android)中创建您自己的 SSH/SFTP 服务器的类。
【讨论】:
链接坏了,现在是nsoftware.com/sftp/sftpserver。还应该提到的是,它具有商业许可证,没有公开定价信息。 @MichaelWyraz 不,那是不同的产品。 SecureBlackbox 就在那里,充满活力和活力。我现在会更新链接。【参考方案6】:http://sourceforge.net/projects/javasecureftpd/
【讨论】:
您提供的链接不是java库,它是一个独立的产品。此外,它似乎没有使用 SFTP,而是使用 FTPS。您是否阅读过有关此产品的任何信息,或者您是否只是在 google 搜索“java secure ftp”时选择了第二个链接? 抱歉,我浏览了一个链接,上面说 javasecureftpd 正在实施 SFTP,我认为确实如此。无论如何,你不必刻薄,我只是想帮助你。【参考方案7】:我正在使用 jftp http://j-ftp.sourceforge.net/ 从 j-ftp-*.tgz/j-ftp/dist 中提取 jftp.jar 唯一的问题 - 他们将 apache 类放在 jar 中(所以我必须手动删除 common-httpclient、log4j 包以避免冲突的依赖项)
【讨论】:
可能是因为问题是关于 SFTP 服务器,而不是客户端。以上是关于Java SFTP 服务器库? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章