JSch - 如何让用户确认主机指纹?

时间:2017-04-26 23:13:06

标签: java android security ssh jsch

在Android应用中,我尝试使用JSch库连接到SSH服务器。远程服务器由用户指定,因此我事先不知道远程指纹。与此同时,我并不想将onCreate设置为否,就像我在很多例子中看到的那样。

我想获取远程服务器指纹,将其显示给用户以供接受。这可能是使用JSch还是常规Java,也许是使用套接字?

以下是您可以尝试的示例,只需将其粘贴到Android活动的new Thread(new Runnable() { @Override public void run() { com.jcraft.jsch.Session session; JSch jsch; try { jsch = new JSch(); jsch.setLogger(new MyLogger()); session = jsch.getSession("git", "github.com", 22); session.setPassword("hunter2"); Properties prop = new Properties(); prop.put("StrictHostKeyChecking", "yes"); session.setConfig(prop); //**Get a host key and show it to the user** session.connect(); // reject HostKey: github.com } catch (Exception e){ LOG.error("Could not JSCH", e); } } }).start(); 中即可:

Projects.detectProjectByKeyword("brumi")

2 个答案:

答案 0 :(得分:3)

好的,我找到了办法。它可能不是最好的方式,但它是 a 方式。在等待用户响应时使用UserInfo.promptYesNo所需looping at the expense of CPU或使用Executor / FutureTask / BlockingQueue的开销。相反,执行连接的异步线程(因为网络任务不能在UI线程上发生)更有利于两次这样做 - 一次到达' break'并让用户接受,第二个成功。我想这是Android的方式'。为此,hostkey需要存储在某处。假设我将它存储在Android的PreferenceManager中,然后从那里抓取密钥,默认为空,如果不可用

String keystring = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("target_hostkey","");

if(!Strings.isNullOrEmpty(keystring)){
    byte[] key = Base64.decode ( keystring, Base64.DEFAULT );
    jsch.getHostKeyRepository().add(new HostKey("github.com", key ), null);
}

接下来,像往常一样继续连接到服务器

session = jsch.getSession("git", "github.com", 22);
session.setPassword("hunter2");

Properties prop = new Properties();
prop.put("StrictHostKeyChecking", "yes");
session.setConfig(prop);
session.connect(); 

但这一次,赶上JSchException。在那里,会话有一个HostKey可用。

catch(final JSchException jex){

    LOG.debug(session.getHostKey().getKey());
    final com.jcraft.jsch.Session finalSession = session;

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            new MaterialDialog.Builder(MyActivity.this)
                    .title("Accept this host with fingerprint?")
                    .negativeText(R.string.cancel)
                    .positiveText(R.string.ok)
                    .content(finalSession.getHostKey().getFingerPrint(jsch))
                    .onPositive(new MaterialDialog.SingleButtonCallback() {
                        @Override
                        public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                            PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit().putString("target_hostkey", finalSession.getHostKey().getKey()).apply();
                        }
                    }).show();
        }
    });

}

在此之后,重新调用Thread或AsyncTask是一个问题,但这次将hostkey添加到JSch的hostkey存储库中。

答案 1 :(得分:1)

两种可能性:

  1. StrictHostKeyChecking设置为ask时,JSch会在确认提示下调用UserInfo.promptYesNo。实施UserInfo interface以向用户显示确认。缺点是您无法以任何方式自定义消息(当然,除非您尝试解析它,依赖于硬编码模板)。

    消息如下:

      

    警告:远程主机识别已更改!
      有可能是某人做的很棒!   有人可能正在偷听你(中间人攻击)!   -key_type-主机密钥也可能刚刚更改   远程主机发送的-key_type-密钥的指纹为
      -key_fprint-
      请联系您的系统管理员   在-file-中添加正确的主机密钥以消除此消息。

    有关示例实现,请参阅official JSch KnownHosts.java example

  2. 甚至在上述情况之前,JSch调用HostKeyRepository.check,传递主机名和密钥。

    您可以实现该接口/方法,以执行您喜欢的任何提示。

  3. 检查Session.checkHost实施。