SSH는 어떻게 동작하는가?

    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  

    1. 클라이언트는 ssh key pair를 생성한다(혹은 이미 소유). private key는 자신이 가지고 있고, public key만 서버에게 전송한다. 
      1. 만약 클라이언트에 private key만 존재하더라도 클라이언트는 public key를 전송할 수 있다. public key는 private key를 통해서 유도해 낼 수 있기 때문이다.
    2. 서버도 자신의 ssh key pair를 생성한다. (혹은 이미 소유). private key는 자신이 가지고 있고, public key만 클라이언트에게 전송한다.
    3. 서버와 클라이언트는 임의의 비밀 값을 각각 생성한다(예를 들어 서버는 비밀 값 a, 클라이언트는 비밀 값 b).
    4. 서버와 클라이언트는 생성한 임의의 비밀 값으로 공개 값을 계산한다. 그리고 서버는 클라이언트의 공개 키로 공개값을 암호화해서 클라이언트에게 전송, 클라이언트는 서버의 공개 키로 공개값을 암호화해서 서버에게 전송한다.
    5. 서버와 클라이언트는 자신의 공개 키로 암호화 된 공개값을 비밀 키로 복호화해서 공개값을 통해 '공유하는 비밀 값'을 가진다. (이 값은 수학적인 연산에 의해 계산된다.)
    6. 공유하는 비밀값으로부터 세션 키가 생성된다.

    여기서 생성된 세션 키는 이후의 모든 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 프로토콜의 해시 함수를 사용한다.
      • 클라이언트는 자신의 개인 키를 이용해 해시 값을 암호화 해서 디지털 서명을 만든다.
    • 클라이언트는 디지털 서명을 세션 키로 암호화해서 서버에게로 전송한다.
    • 서버는 세션키로 서명을 복호화 한 후에, 클라이언트의 공개 키로 서명을 복호화한다. 복호화 된 해시 값과 서버가 생성한 임의의 값의 해시를 비교해서 인증을 완료한다. 

    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 주소나 호스트 이름을 기반으로 인증함. 

    댓글

    Designed by JB FACTORY