Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
swift-nio-ssh — SwiftNIO SSH는 SwiftNIO를 사용한 SSH의 프로그래매틱 구현입니다. | Kitploit
도구/GitHubGitHub/apple/swift-nio-ssh
Encryption/Decryption ToolsNetwork SecurityUtilities & FrameworksAuthenticationRemote Access Tool
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의 프로그래매틱 구현입니다. 즉, 프로그래머가 SSH를 사용하는 엔드포인트를 구현할 수 있게 해주는 API 모음입니다. 중요한 점은 이것이 openssh보다 libssh2에 더 가깝다는 의미입니다. SwiftNIO SSH는 프로덕션 준비가 완료된 SSH 클라이언트와 서버를 제공하지 않지만, 이러한 클라이언트와 서버를 구축하기 위한 구성 요소를 제공합니다.

프로그래매틱 SSH 구현을 제공하는 데는 여러 이유가 있습니다. 그 중 하나는 SSH가 사용자 상호작용성과 독특한 관계를 가지고 있다는 점입니다. 기술 사용자들은 원격 머신에서 명령을 실행하거나 대화형 셸을 실행하기 위해 SSH와 대화형으로 상호작용하는 데 매우 익숙합니다. 이러한 요청에 프로그래매틱으로 응답할 수 있는 능력은 흥미로운 대안적 상호작용 방식을 가능하게 합니다. 이전 예로, Twisted의 Manhole은 [프로그래매틱 SSH 구현인 `conch`](https://twistedmatrix.com/trac/wiki/TwistedConch)를 사용하여 실행 중인 Python 서버 내에서 대화형 Python 인터프리터를 제공하거나, [ssh-chat](https://github.com/shazow/ssh-chat)은 일반 SSH 셸 기능 대신 채팅방을 제공하는 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를 지원합니다:

- 모든 세션 채널 기능(셸 및 exec 채널 요청 포함)
- 직접 및 역방향 TCP 포트 포워딩
- 최신 암호화 프리미티브만 지원: 비대칭 암호화를 위한 주요 NIST 곡선(P256, P384, P521) 기반 Ed25519 및 ECDSA, 대칭 암호화를 위한 AES-GCM, 키 교환을 위한 x25519
- 암호 및 공개 키 사용자 인증
- SwiftNIO 및 Swift Crypto가 지원하는 모든 플랫폼 지원

## SwiftNIO SSH를 사용하려면 어떻게 해야 하나요?

SwiftNIO SSH는 SwiftNIO `ChannelHandler`인 `NIOSSHHandler`를 제공합니다. 이 핸들러는 SSH 프로토콜의 대부분을 직접 구현합니다. 사용자는 SSH 메시지를 직접 생성할 것으로 예상되지 않습니다. 대신 하위 채널과 델리게이트를 통해 `NIOSSHHandler`와 상호작용합니다.

SSH는 다중화 프로토콜입니다. 각 SSH 연결은 적절히 '채널'이라고 불리는 여러 양방향 통신 채널로 세분화됩니다. SwiftNIO SSH는 '하위 채널' 추상화를 사용하여 이 구조를 반영합니다. 피어가 새 SSH 채널을 생성하면 SwiftNIO SSH는 해당 SSH 채널의 모든 트래픽을 나타내는 새 NIO `Channel`을 생성합니다. 이 하위 `Channel` 내에서는 모든 이벤트가 서로에 대해 엄격하게 순서가 지정되지만, 다른 `Channel`의 이벤트는 구현에 의해 자유롭게 인터리브될 수 있습니다.

활성 SSH 연결은 따라서 다음과 같습니다:

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

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

SSH 채널은 채널 유형으로 호출됩니다. NIOSSH는 세 가지 유형을 지원합니다: `session`, `directTCPIP`, `forwardedTCPIP`. 가장 일반적인 채널 유형은 `session`입니다. `session`은 특정 명명된 프로그램이나 셸 등 프로그램 호출을 나타내는 데 사용됩니다. 다른 두 채널 유형은 TCP 포트 포워딩과 관련이 있으며, 나중에 논의됩니다.

SSH 채널은 단일 데이터 유형인 `SSHChannelData`로 작동합니다. 이 구조는 SSH가 일반 채널 데이터와 '확장' 채널 데이터를 모두 지원한다는 사실을 캡슐화합니다. 일반 채널 데이터(`SSHChannelData.DataType.channel`)는 대부분의 핵심 데이터에 사용됩니다. `session` 채널에서 `.channel` 데이터 유형은 표준 입력과 표준 출력에 사용되고, `.stdErr` 데이터 유형은 표준 오류에 사용됩니다(당연히). TCP 포워딩 채널에서는 `.channel` 데이터 유형만 사용되며 포워딩된 데이터를 나타냅니다.

### 채널 이벤트

`session` 채널은 명령의 호출을 나타냅니다. 채널이 정확히 어떻게 작동하는지는 여러 인바운드 사용자 이벤트를 통해 전달됩니다. 다음 이벤트가 중요합니다:

- `SSHChannelRequestEvent.PseudoTerminalRequest`: 의사 터미널 할당을 요청합니다.
- `SSHChannelRequestEvent.EnvironmentRequest`: 명령 호출을 위한 단일 환경 변수를 요청합니다. 항상 명령 자체보다 먼저 전송됩니다.
- `SSHChannelRequestEvent.ShellRequest`: 호출할 명령이 인증된 사용자의 셸이도록 요청합니다.
- `SSHChannelRequestEvent.ExecRequest`: 특정 명령의 호출을 요청합니다.
- `SSHChannelRequestEvent.ExitStatus`: 원격 명령이 종료되었음을 알리고 종료 코드를 전달합니다.
- `SSHChannelRequestEvent.ExitSignal`: 원격 명령이 신호에 응답하여 종료되었음을 나타내고 해당 신호가 무엇인지 전달합니다.
- `SSHChannelRequestEvent.SignalRequest`: 원격 명령에 신호를 보내는 데 사용됩니다.
- `SSHChannelRequestEvent.LocalFlowControlRequest`: 클라이언트가 Ctrl-Q/Ctrl-S 흐름 제어를 자체적으로 수행할 수 있는지 여부를 나타내는 데 사용됩니다.
- `SSHChannelRequestEvent.WindowChangeRequest`: 클라이언트의 터미널 창 크기 변경을 할당된 의사 터미널에 전달하는 데 사용됩니다.
- `SSHChannelRequestEvent.SubsystemRequest`: 특정 하위 시스템의 호출을 요청하는 데 사용됩니다. 이 의미는 개별 사용 사례에 따라 다릅니다.

이 이벤트는 포트 포워딩 메시지에서 사용되지 않습니다. `.session` 유형 채널을 지원하는 SSH 구현은 다양한 방식으로 이러한 이벤트의 대부분 또는 전체를 처리할 준비가 되어 있어야 합니다.

이러한 각 이벤트에는 `wantReply` 필드도 있습니다. 이는 요청이 성공 또는 실패를 나타내는 응답이 필요한지 여부를 나타냅니다. 필요한 경우 다음 두 이벤트가 사용됩니다:

- `ChannelSuccessEvent`, 성공을 전달합니다.
- `ChannelFailureEvent`, 실패를 전달합니다.

### 반 폐쇄 (Half Closure)

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` 채널 유형을 사용하여 클라이언트가 직접 열 수 있습니다.

### 원격 포트 포워딩 및 글로벌 요청

원격 포트 포워딩은 덜 일반적인 상황으로, 클라이언트가 서버에 특정 주소와 포트에서 수신 대기하고 모든 인바운드 연결을 클라이언트로 포워딩하도록 요청합니다. 클라이언트가 이 동작을 요청해야 하므로 글로벌 요청을 사용하여 요청합니다.

글로벌 요청은 `NIOSSHHandler.sendGlobalRequest`를 사용하여 시작되며, `GlobalRequestDelegate`를 통해 수신 및 처리됩니다. 현재 지원되는 글로벌 요청은 두 가지입니다:

- `GlobalRequest.TCPForwardingRequest.listen(host:port:)`: 특정 호스트와 포트에서 수신 대기하도록 서버에 요청합니다.
- `GlobalRequest.TCPForwardingRequest.cancel(host:port:)`: 특정 호스트와 포트에서 수신 대기를 취소하도록 요청합니다.

서버는 `GlobalRequestDelegate`를 사용하여 이러한 요청을 통지받고 응답할 수 있습니다. 여기서 구현할 메서드는 `tcpForwardingRequest(_:handler:promise:)`입니다. 이 델리게이트 메서드는 글로벌 요청이 수신될 때마다 호출됩니다. 요청에 대한 응답은 `promise`에 전달됩니다.

그런 다음 포워딩된 채널은 `.forwardedTCPIP` 채널 유형을 사용하여 서버에서 클라이언트로 전송됩니다.
도구 다운로드