Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
swift-nio-ssh — SwiftNIO SSH 是使用 SwiftNIO 以编程方式实现的 SSH 协议。 | Kitploit
工具/GitHubGitHub/apple/swift-nio-ssh
加密/解密工具网络安全实用工具与框架身份验证远程访问工具
GitHubapple/swift-nio-ssh

swift-nio-ssh

SwiftNIO SSH 是使用 SwiftNIO 以编程方式实现的 SSH 协议。

查看仓库
51379361天前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
# SwiftNIO SSH

本项目包含基于 [SwiftNIO](https://github.com/apple/swift-nio) 的 SSH 支持。

## SwiftNIO SSH 是什么?

SwiftNIO SSH 是 SSH 的一种编程式实现:也就是说,它是一组 API 集合,允许程序员实现能够说 SSH 协议的端点。关键在于,这意味着它更像 libssh2 而不是 openssh。SwiftNIO SSH 并不提供可直接用于生产的 SSH 客户端和服务器,而是提供构建此类客户端和服务器的基础构件。

提供编程式 SSH 实现有很多理由。其中之一是 SSH 与用户交互性有着独特的关系。技术用户非常习惯于以交互方式使用 SSH,无论是在远程机器上运行命令还是运行交互式 shell。具备以编程方式响应这些请求的能力,可以带来有趣的替代交互模式。作为先例,我们可以提到 Twisted 的 Manhole,它使用 [一个名为 `conch` 的编程式 SSH 实现](https://twistedmatrix.com/trac/wiki/TwistedConch) 在运行中的 Python 服务器内提供交互式 Python 解释器;还有 [ssh-chat](https://github.com/shazow/ssh-chat),一个提供聊天室而非常规 SSH shell 功能的 SSH 服务器。在 TCP 转发方面也可以设想出创新性的用途。

提供编程式 SSH 的另一个很好的理由是,服务之间以涉及运行命令的方式进行交互并不少见。虽然 `Process` 解决了本地场景下的需求,但有时需要调用的命令位于远程。虽然 `Process` 可以启动一个 `ssh` 客户端作为子进程来执行这种调用,但直接调用 SSH 本身显然要简单得多。这正是 [`libssh2`](https://www.libssh2.org) 的目标用例。SwiftNIO SSH 提供了与 libssh2 的网络和加密层等价的功能,使得有动力的用户能够直接在 Swift 服务内驱动 SSH 会话。

SwiftNIO SSH 的最新版本支持 Swift 5.9 及更高版本。SwiftNIO SSH 各版本支持的最低 Swift 版本如下所示:

SwiftNIO SSH        | 最低 Swift 版本
--------------------|----------------------
`0.0.0  ..< 0.3.0`  | 5.1
`0.3.0  ..< 0.4.0`  | 5.2
`0.4.0  ..< 0.5.0`  | 5.4
`0.5.0  ..< 0.6.2`  | 5.5.2
`0.6.2  ..< 0.9.0`  | 5.6
`0.9.0  ..< 0.9.2`  | 5.8
`0.9.2  ..< 0.10.0` | 5.9
`0.10.0 ... 0.12.0` | 5.10
`0.12.0 ..< 0.13.0` | 6.0
`0.13.0 ..<`        | 6.1

## SwiftNIO SSH 支持什么?

SwiftNIO SSH 支持 SSHv2,并具有以下功能集:

- 所有会话通道功能,包括 shell 和 exec 通道请求
- 直接与反向 TCP 端口转发
- 仅使用现代密码学原语:非对称加密使用 Ed25519 和基于主要 NIST 曲线(P256、P384、P521)的 ECDSA,对称加密使用 AES-GCM,密钥交换使用 x25519
- 密码和公钥用户认证
- 支持 SwiftNIO 和 Swift Crypto 所支持的所有平台

## 如何使用 SwiftNIO SSH?

SwiftNIO SSH 提供一个 SwiftNIO `ChannelHandler`,即 `NIOSSHHandler`。该 handler 直接实现了 SSH 协议的大部分内容。用户不需要直接生成 SSH 消息;相反,他们通过子通道(child channels)和委托(delegates)与 `NIOSSHHandler` 进行交互。

SSH 是一种多路复用协议:每个 SSH 连接被细分为多个双向通信通道,恰如其分地称为“通道”(channels)。SwiftNIO SSH 通过使用“子通道”(child channel)抽象来反映这种构造。当对端创建一个新的 SSH 通道时,SwiftNIO SSH 会创建一个新的 NIO `Channel`,用于表示该 SSH 通道上的所有流量。在这个子 `Channel` 内,所有事件彼此之间是严格有序的;但是,不同 `Channel` 中的事件可以由实现自由地交错。

因此,一个活动的 SSH 连接看起来像这样:

```
┌ ─ NIO Channel ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐

│     ┌────────────────────────────────┐    │
      │                                │
│     │                                │    │
      │                                │
│     │                                │    │
      │         NIOSSHHandler          │───────────────────────┐
│     │                                │    │                  │
      │                                │                       │
│     │                                │    │                  │
      │                                │                       │
│     └────────────────────────────────┘    │                  │
                                                               │
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘                  │
                                                               │
                                                               │
                                                               │
                                                               │
                                                               ▼
                     ┌── SSH Child Channel ─────────────────────────────────────────────────────────────┐
                     │                                                                                  │
                     │   ┌────────────────────────────────┐      ┌────────────────────────────────┐     ├───┐
                     │   │                                │      │                                │     │   │
                     │   │                                │      │                                │     │   ├───┐
                     │   │                                │      │                                │     │   │   │
                     │   │                                │      │                                │     │   │   │
                     │   │          User Handler          │      │          User Handler          │     │   │   │
                     │   │                                │      │                                │     │   │   │
                     │   │                                │      │                                │     │   │   │
                     │   │                                │      │                                │     │   │   │
                     │   │                                │      │                                │     │   │   │
                     │   └────────────────────────────────┘      └────────────────────────────────┘     │   │   │
                     │                                                                                  │   │   │
                     └───┬──────────────────────────────────────────────────────────────────────────────┘   │   │
                         │                                                                                  │   │
                         └───┬──────────────────────────────────────────────────────────────────────────────┘   │
                             │                                                                                  │
                             └──────────────────────────────────────────────────────────────────────────────────┘
```

SSH 通道通过通道类型(channel type)来调用。NIOSSH 支持三种类型:`session`、`directTCPIP` 和 `forwardedTCPIP`。最常见的通道类型是 `session`:`session` 用于表示某个程序的调用,无论是特定命名的程序还是 shell。另外两种通道类型与 TCP 端口转发相关,将在后面讨论。

SSH 通道基于单一数据类型进行操作:`SSHChannelData`。该结构封装了 SSH 同时支持常规和“扩展”通道数据这一事实。常规通道数据(`SSHChannelData.DataType.channel`)用于绝大部分核心数据。在 `session` 通道中,`.channel` 数据类型用于标准输入和标准输出:`.stdErr` 数据类型则用于标准错误(理所当然)。在 TCP 转发通道中,`.channel` 数据类型是唯一使用的类型,表示被转发数据。

### 通道事件

`session` 通道表示对一条命令的调用。通道具体如何运作,通过若干入站用户事件(inbound user events)来传达。以下事件很重要:

- `SSHChannelRequestEvent.PseudoTerminalRequest`:请求分配一个伪终端。
- `SSHChannelRequestEvent.EnvironmentRequest`:为命令调用请求一个环境变量。总是在命令本身之前发送。
- `SSHChannelRequestEvent.ShellRequest`:请求将已认证用户的 shell 作为要调用的命令。
- `SSHChannelRequestEvent.ExecRequest`:请求调用特定命令。
- `SSHChannelRequestEvent.ExitStatus`:用于通知远程命令已退出,并传递退出码。
- `SSHChannelRequestEvent.ExitSignal`:用于指示远程命令因某个信号而终止,以及该信号是什么。
- `SSHChannelRequestEvent.SignalRequest`:用于向远程命令发送信号。
- `SSHChannelRequestEvent.LocalFlowControlRequest`:用于指示客户端是否能够自行执行 Ctrl-Q/Ctrl-S 流控制。
- `SSHChannelRequestEvent.WindowChangeRequest`:用于将客户端终端窗口大小的变化传达给已分配的伪终端。
- `SSHChannelRequestEvent.SubsystemRequest`:用于请求调用特定子系统。其含义因具体用例而异。

这些事件在端口转发消息中不会使用。支持 `.session` 类型通道的 SSH 实现需要准备好以各种方式处理其中大部分或全部事件。

这些事件也都有一个 `wantReply` 字段。它指示该请求是否需要回复来表示成功或失败。如果需要,则会使用以下两个事件:

- `ChannelSuccessEvent`,用于传达成功。
- `ChannelFailureEvent`,用于传达失败。

### 半关闭

SSH 网络协议在子通道中普遍使用半关闭。NIO `Channel` 默认情况下通常禁用半关闭支持,SwiftNIO SSH 在其子通道中也遵循这一默认设置。但是,如果你将此设置保留为默认值,SSH 子通道的行为将极其出人意料。因此,强烈建议为所有子通道启用半关闭支持:

```swift
channel.setOption(ChannelOptions.allowRemoteHalfClosure, true)
```

然后这会使用标准的 NIO 半关闭支持。远端发送 EOF 将通过一个入站用户事件 `ChannelEvent.inputClosed` 来传达。若想自己发送 EOF,请调用 `close(mode: .output)`。

### 用户认证

用户认证是 SSH 的关键组成部分。为了管理它,SwiftNIO SSH 使用一对委托协议:`NIOSSHClientUserAuthenticationDelegate` 和 `NIOSSHServerUserAuthenticationDelegate`。客户端和服务器应提供这些委托协议的实现来管理用户认证。

客户端协议很直接:SwiftNIO SSH 会在委托上调用 `nextAuthenticationType(availableMethods:nextChallengePromise:)` 方法。`availableMethods` 将是 `NIOSSHAvailableUserAuthenticationMethods` 的一个实例,用于传达服务器建议可接受的认证方法。然后,委托可以用一个新的认证请求来兑现 `nextChallengePromise`,或者用 `nil` 表示客户端已经没有可尝试的方法。

服务器协议则更复杂。委托必须提供一个 `supportedAuthenticationMethods` 属性,用于传达该委托支持哪些认证方法。然后,每次客户端发送用户认证请求时,都会调用 `requestReceived(request:responsePromise:)` 方法。由于允许客户端并行发出认证请求,因此该方法可能会被并行调用多次。`responsePromise` 应当以认证结果来成功完成。结果有三种:`.success` 和 `.failure` 直截了当,但原则上服务器可以使用 `.partialSuccess(remainingMethods:)` 要求多次挑战。

### 直接端口转发

直接端口转发是从客户端到服务器的端口转发。在这种模式下,传统上客户端会监听一个本地端口,并将入站连接转发到服务器。它会请求服务器将这些连接作为出站连接转发到特定的主机和端口。

客户端可以使用 `.directTCPIP` 通道类型直接打开这些通道。

### 远程端口转发与全局请求

远程端口转发是一种不太常见的情况,即客户端要求服务器监听特定地址和端口,并将所有入站连接转发给客户端。由于客户端需要请求此行为,因此它通过全局请求(global requests)来实现。

全局请求通过 `NIOSSHHandler.sendGlobalRequest` 发起,并由 `GlobalRequestDelegate` 接收和处理。目前支持两种全局请求:

- `GlobalRequest.TCPForwardingRequest.listen(host:port:)`:请求服务器在给定主机和端口上监听。
- `GlobalRequest.TCPForwardingRequest.cancel(host:port:)`:请求取消在给定主机和端口上的监听。

服务器可以通过 `GlobalRequestDelegate` 被通知并响应这些请求。这里要实现的方法是 `tcpForwardingRequest(_:handler:promise:)`。任何时候收到全局请求,都会调用此委托方法。对该请求的响应会传入 `promise`。

然后,转发通道通过 `.forwardedTCPIP` 通道类型从服务器发送到客户端。
下载工具