【问题标题】:Reverse Tunnel over JSCH (SSH) and HTTPS基于 JSCH (SSH) 和 HTTPS 的反向隧道
【发布时间】:2015-07-28 06:51:15
【问题描述】:

我必须实现从客户端到服务器的反向隧道。我使用JSCH 和以下命令

session.setPortForwardingR(rport, lhost, lport);

它有效(另见Reverse SSH tunnel with JSCH Java)!

接下来我必须通过 HTTPS 流 2-way 身份验证来传输我的 ssh 会话:

client -> firewall -> apache https -> ssh server 

----------------------> HTTPS
====================================> SSH
---------------------->

我在找

  1. 一小段java代码将SSH封装成HTTPS
  2. 2路HTTPS认证
  3. APACHE 配置

可能的解决方案:

1) HTTPS 隧道

  1. JHTTPTunnel,但它基于 J2ME,不支持 SSL(另见 Java Http TunnelingIs there an Java library for sending binary data over HTTP, HTTP Tunneling?
  2. JOD,但不支持 SSL

3) APACHE 配置

  1. 也许这个configuration 有效,但我必须尝试
## Load the required modules.
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so

## Listen on port 8443 (in addition to other ports like 80 or 443)
Listen 8443

<VirtualHost *:8443>

  ServerName youwebserver:8443
  DocumentRoot /some/path/maybe/not/required
  ServerAdmin admin@example.com

  ## Only ever allow incoming HTTP CONNECT requests.
  ## Explicitly deny other request types like GET, POST, etc.
  ## This tells Apache to return a 403 Forbidden if this virtual
  ## host receives anything other than an HTTP CONNECT.
  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} !^CONNECT [NC]
  RewriteRule ^/(.*)$ - [F,L]

  ## Setup proxying between youwebserver:8443 and yoursshserver:22

  ProxyRequests On
  ProxyBadHeader Ignore
  ProxyVia Full

  ## IMPORTANT: The AllowCONNECT directive specifies a list
  ## of port numbers to which the proxy CONNECT method may
  ## connect.  For security, only allow CONNECT requests
  ## bound for port 22.
  AllowCONNECT 22

  ## IMPORTANT: By default, deny everyone.  If you don't do this
  ## others will be able to connect to port 22 on any host.
  <Proxy *>
    Order deny,allow
    Deny from all
  </Proxy>

  ## Now, only allow CONNECT requests bound for kolich.com
  ## Should be replaced with yoursshserver.com or the hostname
  ## of whatever SSH server you're trying to connect to.  Note
  ## that ProxyMatch takes a regular expression, so you can do
  ## things like (kolich\.com|anothersshserver\.com) if you want
  ## to allow connections to multiple destinations.
  <ProxyMatch (kolich\.com)>
    Order allow,deny
    Allow from all
  </ProxyMatch>

  ## Logging, always a good idea.
  LogLevel warn
  ErrorLog logs/yourwebserver-proxy_error_log
  CustomLog logs/yourwebserver-proxy_request_log combined

</VirtualHost>

【问题讨论】:

    标签: java apache ssh https http-tunneling


    【解决方案1】:

    自己提出的解决方案还可以,我认为是基于Implement HTTPS tunneling with JSSE

    基本步骤是:

    1. 为 JSCH 定义连接工厂
    2. 打开一个 SSL Socket 并调用"CONNECT " + host + ":" + port

    在服务器端捕获所有调用“CONNECT”的请求并启用 22 SSH 端口。

    但你还必须考虑以下问题:

    1. 调整超时,因为 SSL 握手时间很长
    2. 启用 2-way 身份验证或所有人都可以连接到您的 22 台服务器: Using client/server certificates for two way authentication SSL socket on Android

    【讨论】:

      【解决方案2】:

      很遗憾,没有人试图回复;我找到了解决方案。

      解决方案基于HTTP 1.1CONNECT命令,不支持直接隧道。

      在 Java 客户端上

               // Install the all-trusting trust manager
               final SSLContext sc = SSLContext.getInstance("SSL");
               sc.init(null, trustAllCerts, new java.security.SecureRandom());
               JSch jsch = new JSch();
               Session session = jsch.getSession("root", "SSH-server", 22);
      
               session.setSocketFactory(new SocketFactory() {
                Socket tunnel = null;
      
                public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
      
                    SSLSocketFactory ssf = sc.getSocketFactory();
      
                    // HTTP
                    tunnel = ssf.createSocket(System.getProperty("https.proxyHost"), Integer.getInteger("https.proxyPort"));
                    tunnel.setKeepAlive(true);
      
                    doTunnelHandshake(tunnel, host, port);
                    System.out.println(tunnel + " connect " + tunnel.isConnected());
                    return tunnel; // dummy
                }
      
                public InputStream getInputStream(Socket socket) throws IOException {
                    System.out.println(tunnel + " getInputStream " + socket.isConnected());
                    return tunnel.getInputStream();
                }
      
                public OutputStream getOutputStream(Socket socket) throws IOException {
                    System.out.println("getOutputStream");
                    return socket.getOutputStream();
                }           });
      
            session.connect();
      
            try {
                session.setPortForwardingR(3391, "localhost", 3389);
            ....
      

      在哪里

        private static void doTunnelHandshake(Socket tunnel, String host, int port) throws IOException {
              OutputStream out = tunnel.getOutputStream();
              String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n" + 
             "User-Agent: " +
             sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n\r\n";
              byte b[];
              try {
      
                    b = msg.getBytes("ASCII7");
              } catch (UnsupportedEncodingException ignored) {
                    /*
                     * If ASCII7 isn't there, something serious is wrong, but Paranoia
                     * Is Good (tm)
                     */
                    b = msg.getBytes();
              }
              out.write(b);
              out.flush();
      
              /*
               * We need to store the reply so we can create a detailed error message
               * to the user.
               */
              byte reply[] = new byte[200];
              int replyLen = 0;
              int newlinesSeen = 0;
              boolean headerDone = false; /* Done on first newline */
      
              InputStream in = tunnel.getInputStream();
              boolean error = false;
      
              while (newlinesSeen < 2) {
                    int i = in.read();
                    if (i < 0) {
                          throw new IOException("Unexpected EOF from proxy");
                    }
                    if (i == '\n') {
                          headerDone = true;
                          ++newlinesSeen;
                    } else if (i != '\r') {
                          newlinesSeen = 0;
                          if (!headerDone && replyLen < reply.length) {
                                reply[replyLen++] = (byte) i;
                          }
                    }
              }
      
              /*
               * Converting the byte array to a string is slightly wasteful in the
               * case where the connection was successful, but it's insignificant
               * compared to the network overhead.
               */
              String replyStr;
              try {
                    replyStr = new String(reply, 0, replyLen, "ASCII7");
              } catch (UnsupportedEncodingException ignored) {
                    replyStr = new String(reply, 0, replyLen);
              }
      
              System.out.println(replyStr);
      
              /* We asked for HTTP/1.0, so we should get that back */
              if (!replyStr.startsWith("HTTP/1.0 200")) {
                    throw new IOException("Unable to tunnel for " + host + ":" + port + ".  Proxy returns \"" + replyStr + "\"");
              }
      
              /* tunneling Handshake was successful! */
        }
      

      关于 apache 配置

      添加 ssl 支持

       SSLEngine on
       SSLCertificateFile "conf/ssl.crt/server.crt"
       SSLCertificateKeyFile "conf/ssl.key/server.key"
      

      这里是结果

      Connecting to localhost port 22
      HTTP/1.0 200 Connection Established
      ....
      Authentications that can continue: password
      Next authentication method: password
      Authentication succeeded (password).
      Connected
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-06
        • 2015-03-09
        • 1970-01-01
        • 2012-06-06
        • 2018-09-01
        • 2015-07-27
        • 2020-09-15
        • 2010-09-27
        相关资源
        最近更新 更多