SSH는 어떻게 동작하는가?
- 카테고리 없음
- 2024. 8. 24.
1. Establish TCP Connection
클라이언트가 서버에게 SSH 요청을 보내면 가장 먼저 서버 - 클라이언트 간의 TCP 연결이 이루어진다. 서버는 주로 Port 22를 listen하고 있고, 클라이언트는 임의의 Port에 바인딩 되어서 TCP Connection이 생성된다. TCP Connection이 생성되면, SSH 세션이 생성된다. 이 SSH 세션 내에서 다음 작업들을 진행하게 될 것이다
- 세션 초기화
- 클라이언트 - 서버 키 교환
- 세션 키 생성
- 신원 인증 등등
2. Supported Version Negotiation
TCP 연결이 설정되면 클라이언트 - 서버는 SSH 프로토콜 버전을 서로 교환한다. 메세지 형식은 'SSH-2.0-'으로 시작하는 문자열을 교환하는데, 예를 들면 'SSH-2.0-OpenSSH_8.1' 같은 문자열이 될 수 있다. 클라이언트 - 서버는 이 메세지를 서로 교환해서 어떤 SSH 프로토콜 버전을 사용할지 결정한다. 만약 버전이 호환되지 않는다면 이 단계에서 연결이 종료된다.
3. Supported algorithms negotiation
이 단계에서 클라이언트 - 서버는 사용할 암호화 알고리즘, 메세지 인증코드(MAC) 알고리즘, 압축 알고리즘 등을 협상한다.
- 암호화 알고리즘은 세션 키가 생성된 이후 클라이언트 - 서버 간에 전송되는 모든 메세지를 암호화할 때 사용하는 알고리즘이다. AES, ChaCha20 같은 알고리즘이 예시다.
- MAC(메세지 인증코드) 알고리즘은 보낸 메세지를 잘 받았다는 것을 검증하기 위한 용도로 사용된다. 메세지의 각 패킷의 MAC을 계산하고, 이 MAC을 패킷에 추가하여 함께 전송한다. 그리고 받은 쪽은 데이터 패킷의 MAC을 다시 계산하고, 전송된 MAC과 비교해서 데이터가 정상인지 확인한다. HMAC-SHA1, HMAC-SHA2 같은 알고리즘이 예시다.
4~5. Generate key pairs + Send public Key
- 클라이언트는 ssh key pair를 생성한다(혹은 이미 소유). private key는 자신이 가지고 있고, public key만 서버에게 전송한다.
- 만약 클라이언트에 private key만 존재하더라도 클라이언트는 public key를 전송할 수 있다. public key는 private key를 통해서 유도해 낼 수 있기 때문이다.
- 서버도 자신의 ssh key pair를 생성한다. (혹은 이미 소유). private key는 자신이 가지고 있고, public key만 클라이언트에게 전송한다.
- 서버와 클라이언트는 임의의 비밀 값을 각각 생성한다(예를 들어 서버는 비밀 값 a, 클라이언트는 비밀 값 b).
- 서버와 클라이언트는 생성한 임의의 비밀 값으로 공개 값을 계산한다. 그리고 서버는 클라이언트의 공개 키로 공개값을 암호화해서 클라이언트에게 전송, 클라이언트는 서버의 공개 키로 공개값을 암호화해서 서버에게 전송한다.
- 서버와 클라이언트는 자신의 공개 키로 암호화 된 공개값을 비밀 키로 복호화해서 공개값을 통해 '공유하는 비밀 값'을 가진다. (이 값은 수학적인 연산에 의해 계산된다.)
- 공유하는 비밀값으로부터 세션 키가 생성된다.
여기서 생성된 세션 키는 이후의 모든 SSH 통신을 암호화 하는데 사용된다.
6. Initiate a login request (User Authentication Layer 시작)
클라이언트는 서버에게 세션키를 이용해 자신의 공개키를 암호화해서 전송한다. 이 때, 클라이언트의 공개키는 서버의 ~/.ssh/authorized_keys에 등록되어 있어야만 한다.
7. Found matching key, encryt message with public key. ~ 11. verifies the clients decryption is correct
실제 과정은 이 설명과는 다른 것 같다. 실제 과정은 아래와 같다.
- 서버는 클라이언트가 제시한 공개 키를 '클라이언트의 신원'을 확인하는데 사용한다. 구체적인 방법은 클라이언트가 전송한 public key가 authorized_keys에 파일에 있는지 확인한다.
- 클라이언트의 공개 키를 ~/.ssh/authorized_keys에 있는 것을 확인하면 서버는 임의의 값을 생성한다.
- 서버는 생성한 임의의 값을 세션 키로 암호화해서 클라이언트에게 전송한다.
- 클라이언트는 세션 키를 이용해 임의의 값을 복호화하고, 임의의 값에 자신의 개인 키로 서명을 한다.
- 서명은 임의의 값을 특정 해시 함수(SHA-256 같은 것들)로 해시한 값이다. 해시값은 원본 데이터를 고정 길이의 값으로 변환한 값이다. (예를 들어 SHA-256 해시함수는 임의의 길이의 데이터를 입력 받아 항상 256 비트 길이의 해시 값을 생성함.)
- 이 때 사용하는 해시 함수는 Algorithm negotiation 단계에서 협상한 MAC 프로토콜의 해시 함수를 사용한다.
- 클라이언트는 자신의 개인 키를 이용해 해시 값을 암호화 해서 디지털 서명을 만든다.
- 서명은 임의의 값을 특정 해시 함수(SHA-256 같은 것들)로 해시한 값이다. 해시값은 원본 데이터를 고정 길이의 값으로 변환한 값이다. (예를 들어 SHA-256 해시함수는 임의의 길이의 데이터를 입력 받아 항상 256 비트 길이의 해시 값을 생성함.)
- 클라이언트는 디지털 서명을 세션 키로 암호화해서 서버에게로 전송한다.
- 서버는 세션키로 서명을 복호화 한 후에, 클라이언트의 공개 키로 서명을 복호화한다. 복호화 된 해시 값과 서버가 생성한 임의의 값의 해시를 비교해서 인증을 완료한다.
12. session request and response
서버는 신원 검증이 완료되면 다음 형태로 응답한다.
- 인증 성공 : SSH_MSG_USERAUTH_SUCCESS 메세지 전송
- 인증 실패 : SSH_MSG_USERAUTH_FAILURE 메세지 전송. 이 메세지에는 클라이언트가 사용할 수 있는 다른 인증 방법들이 포함됨.
13. send encrypted commands ~
이제 하나의 SSH 세션 내에서 여러 SSH 채널을 생성해서 여러 작업을 동시에 처리할 수 있다. 예를 들어 아래 작업들을 각각 처리할 수 있게 된다.
- 터미널 채널 : 원격 쉘을 사용할 수 있음.
- 포트 포워딩 채널 : 로컬 네트워크의 포트를 원격 서버의 포트와 연결
- SCP : 파일 복사 등
각 채널은 독립적으로 암호화(세션 키를 통해)되고 관리된다.
헷갈리는 부분
- 하나의 TCP 연결에서는 하나의 SSH 세션만 생성된다.
- SSH 세션은 클라이언트 - 서버 간에 설정된 보안 연결을 의미한다.
- 하나의 SSH 세션에서는 여러 개의 SSH 채널이 생성될 수 있다.
- SSH 채널은 SSH 세션 내에서 독립적으로 관리되는 가상의 데이터 통로를 의미한다. 즉, 하나의 SSH 세션 내에서 논리적으로 여러 SSH 채널을 열어 각각의 채널에서 별개의 작업을 진행할 수 있다.
- 세션 키가 생성된 후의 암호화는 '메세지를 세션 키를 이용해 특정 암호화 알고리즘을 이용해 암호화'하는 것을 의미한다.
사용 가능한 기타 인증 방법
- 비밀번호
- GSSAPI (Generic Security Services Application Program Interface): 주로 Krb5 기반의 인증 시스템에서 사용됨.
- 이중 인증(2FA, Two-Factor Authentication)
- Host-based 인증: 서버가 클라이언트의 호스트를 신뢰하여 인증하는 방식으로, 클라이언트의 IP 주소나 호스트 이름을 기반으로 인증함.