본문 바로가기

SEC

[서버보안] SSH #1 - SSH 원리

SSH(Secure Shell) : 시큐어 셸

기존 Telnet, Rlogin, RSH를 대체하기 위해 만들어졌으며 네트워크 상의 다른 PC나 서버에 로그인, 원격 명령 실행, 파일 전송을 수행할 수 있는 프로토콜이다.

기존의 원격 접속 프로토콜인 Telnet, Rlogin, RSH는 데이터 전송 시 평문으로 전송되기 때문에 스니핑을 통해 데이터가 노출되기 쉬운 문제점을 갖고 있었다.

SSH 프로토콜은 안전한 원격 접속과 보호되지 않은 네트워크에서 안전한 네트워크 서비스를 제공하기 위해 암호화를 사용한다. 

암호화를 통해 호스트(클라이언트)와 원격지(서버) 간의 연결(사용자 인증, 명령, 파일 전송)을 네트워크 공격으로부터 보호할 수 있다.

 

SSH 프로토콜의 일반적인 사용은 다음과 같다.

  • 원격 접속 사용자 및 자동화 프로세스의 접근 시
  • 자동화된 파일 전송 시
  • 원격 명령 실행 시
  • 네트워크 인프라와 중요 시스템 관리 시

이러한 상황에서 안전한 통신을 위해 SSH 프로토콜을 사용한다.

 

SSH 작동 원리

SSH 프로토콜은 클라이언트-서버 모델로 동작하며 대칭키 방식, 비대칭키 방식, 해시 알고리즘을 사용하여 인증 및 암호화를 수행한다.

대칭키 방식은 클라이언트-서버 간 전체 연결을 암호화에 사용되며,

비대칭키 방식은 키 교환, 클라이언트 인증, 서버 인증에 사용되고,

해시 알고리즘은 패킷의 무결성을 확인하기 위해 사용된다. (HMAC : Hash based Message Authenticated Codes)

 

[출처] ssh.com

 

1. 클라이언트는 서버에 원격 접속하기 위해 연결을 설정하는 프로세스를 시작한다.

 

SSH 프로토콜은 기본적(Default)으로 TCP 22번 포트를 사용하여 통신한다.

클라이언트가 서버에 원격 접속하기 위해 서버의 TCP 22번 포트로 SSH 접속 요청을 보내는 것이 SSH 연결의 첫 단계이다.

서버는 클라이언트에게 서버가 지원하는 프로토콜의 버전을 응답으로 보내준다.

클라이언트는 서버가 지원하는 프로토콜의 버전 중 자신과 일치하는 것이 있다면 연결을 지속한다. (버전 교환)

 

 

2. 서버는 자신의 공개키를 클라이언트에게 전송한다.

 

서버는 클라이언트로부터 SSH 접속 요청을 받고 자신의 공개키를 클라이언트에게 전송하고 클라이언트는 서버로부터 받은 공개키를 로컬에 저장한다.

클라이언트는 원격 접속하는 서버들의 공개키를 로컬 사용자 홈 디렉터리의 .ssh 경로 내의 known_hosts 파일에 저장하고 있다.

※ 클라이언트 사용자의 known_hosts 경로(Default)

<Linux>
일반계정  : /home/USER/.ssh/known_hosts
root 계정 : /root/.ssh/known_hosts		

<Window>
사용자    : %USERNAME%\.ssh\known_hosts

 

 

 

3. 클라이언트와 서버는 여러 Parameter들을 주고 받으며 보안 채널을 확립한다.

 

3.1 올바른 서버인지 확인(클라이언트 관점) 

 

클라이언트는 SSH로 원격 접속하려고 하는 서버가 올바른 서버인지 확인할 필요가 있다.

이를 위해 클라이언트는 known_hosts 파일에 존재하는 서버의 공개키를 통해 정상적인 서버인지 확인하는 작업을 수행한다.

확인 단계는 다음과 같다.

  1. 클라이언트에서 난수 생성, 난수 해시값 생성 및 저장
  2. 난수를 서버의 공개키로 암호화 후 서버에 전송
  3. 서버에서 서버의 개인키로 데이터를 복호화하여 난수 추출
  4. 서버에서 복호화된 난수 해시값을 생성 후 클라이언트에게 전송
  5. 클라이언트에 저장된 난수 해시값과 서버에서 받은 난수 해시값을 비교
  6. 동일할 시 올바른 서버 확인

 

3.2 암호화된 통신을 위한 세션키 생성(대칭키 생성)

 

세션키는 대칭키로 전체 세션을 암호화하는데 사용되며 모든 통신을 암호화 한다.

대칭키는 비대칭키에 비해 빠르고 컴퓨팅 파워가 더 적게 든다는 장점을 가지고 있다.

그러나 대칭키가 유출되었을 경우 공격자가 암호화된 모든 통신을 복호화할 수 있는 치명적인 문제점을 가지고 있다.

이를 해결하기 위해 클라이언트와 서버는 키 교환 알고리즘을 통해 안전하게 대칭키를 공유한다.

 

SSH에서 사용하는 대표적인 환 알고리즘인 디피-헬만(Diffie-Hellman : DH) 알고리즘은 상대방의 공개키와 나의 개인키를 통해 대칭키를 얻어는 방법이다.

이 단계에서 클라이언트와 서버는 임시 비대칭키 방식의 키 쌍을 생성하하고 공개 키를 교환한다.

DH를 통해 클라이언트와 서버는 대칭키인 세션키를 공유하게 되고 이후 모든 통신은 세션키를 통해 암호화된다.

 

[주의] 대칭키 교환에 사용되는 키 쌍은 서버와 클라이언트 인증에 사용되는 SSH 키 쌍과 다름

 

SSH가 DH를 통해 얻은 대칭키는 개별 세션에 대해 생성되며 더 이상 필요하지 않은 즉시 사라진다. 

따라서 클라이언트나 서버의 개인키가 유출되어도 이전 세션키를 통해 수행한 통신 내용을 복호화할 수 없다.

이는 TLS 세션에서도 사용되는 구성으로 인증서에 만료 날짜가 있는 경우 개인키는 중간자 공격으로 인해 유출되어도 인증서가 만료되었을 시 사용할 수 없으므로 만료 후에는 강한 보안 유지를 하지 않아도 된다.

 

※ RSA를 통해 세션키를 암호화 했을 시에는 개인키가 유출되면 세션키를 복호화하고 전체 통신을 읽을 수 있다.

   

암호화 방식이 정해지고 난 후에는 전송되는 메시지에 MAC(Message Authentication Code)가 포함되어 있어야 상대방이 패킷의 무결성을 확인할 수 있다.

MAC은 패킷의 마지막 부분에 위치하여 세션키로 암호화된 영역 바깥에서 전송되며, 일반적으로 데이터를 먼저 암호화하고 MAC을 계산하는 방법을 권장한다.

MAC은 공유 세션키와 메시지의 패킷 시퀀스 번호 및 실제 메시지 내용으로부터 계산되고 데이터의 무결성 및 통신 인증 확인 목적으로 사용된다.

 

 

3.3 서버에 접근할 수 있는 클라이언트인지 확인(서버 관점)

 

서버 또한 자신에게 접속하려는 클라이언트가 자신에게 접근할 수 있는 권한이 있는지 확인하는 단계가 필요하다.

 

가장 간단한 방법으로 패스워드 인증이 있다.

서버는 단순히 로그인하려는 계정의 암호를 묻고 클라이언트가 입력한 비밀번호는 세션키를 통해 암호화되고 전송되어 외부로부터 안전하게 보호된다.

패스워드가 암호화되지만 패스워드의 복잡성 설정의 한계가 있기 때문에 일반적으로 이 방법을 사용하지 않는 것이 좋다.

자동화된 스크립트를 통해 일반적인 길이의 패스워드는 공격에 의해 해제될 수 있다.

 

가장 많이 사용되고 권장되는 방법은 SSH 키 쌍을 사용하는 것이다.

이 방법을 사용하기 위해서는 클라이언트 측에서도 SSH 키 쌍을 생성해야 한다.

SSH 키 쌍을 통한 클라이언트 인증은 앞서 살펴본 올바를 서버인지 확인하는 과정과 비슷하다.

  1. 클라이언트는 인증할 키 쌍의 ID를 서버에 전송
  2. 서버는 클라이언트가 접속하고자 하는 계정의 .ssh/authorized_keys 파일을 확인
  3. ID에 매칭되는 공개키가 있을 시, 서버는 난수를 생성하고 클라이언트의 공개키로 암호화
  4. 서버는 클라이언트에게 암호화된 메시지 전송
  5. 클라이언트의 개인키를 통해 암호화된 메시지를 복호화하여 난수 추출
  6. 클라이언트는 난수를 세션키와 결합하여 해시값 계산 후 서버 전송
  7. 서버는 저장된 난수와 세션키를 결합하여 해시값 계산 후 비교
  8. 일치할 시 클라이언트 인증

이와 같이 비대칭키를 이용하여 클라이언트가 개인키를 가지고 있는 정상적인 클라이언트라고 증명할 수 있다.

 

 

4. 클라이언트가 서버에 원격 접속을 할 수 있다.

 

이제 세션키를 통해 클라이언트와 서버는 안전한 네트워크 통신을 수행할 수 있다.

 


 

※ 비대칭키 방식 정리

  • 공개키로 암호화한 내용은 공개키로 복호화할 수 없고 개인키로 복호화가 가능하다.
  • 개인키로 암호화한 내용은 개인키로 복호화할 수 없고 공개키로 복호화가 가능하다.

비대칭키 시스템에서 개인키는 자신만 가지고 있는 단일 소유권이고 공개키는 여러 사용자가 소유할 수 있는 분산 소유권이다.

두개의 노드가 통신한다고 했을 때 서로의 공개키로 암호화하여 송신한다면, 개인키를 가지고 있는 수신자를 제외하고 다른 노드는 통신 내용을 복호화할 수 없다.

그러나 개인키로 암호화하여 송신한다면, 공개키를 가지고 있는 모든 노드들이 통신 내용을 복호화할 수 있을 것이다.

그래서 개인키는 메시지에 서명하는 용도로 사용하고 통신 시 암호화에 사용하지 않는다.

메시지 서명은 작성자가 해시값을 개인키로 암호화하여 모든 사용자가 공개키로 해시값을 복호화하고 수신된 해시값과 비교하여 올바른 작성자임을 증명하는 것이다.

(= 공개키 소유자는 서명된 메시지의 출처가 개인키 소유자라는 것을 확인할 수 있다.)

 

 

※ 키교환 과정 (Elliptic Curve Diffie-Hellman 방식)

  • 클라이언트와 서버가 서로에게 SSH_MSG_KEX_INIT 메시지를 전송 (암호화 방식 리스트 포함)
  • 양쪽 모두 동일한 알고리즘을 사용하여 암호화 지원 목록에서 선택

  • 클라이언트는 비대칭키 키 쌍(공개키, 개인키) 생성 → 사용 후 삭제 (키 교환에만 사용되고 나중에 폐기)
  • 클라이언트는 SSH_MSG_KEX_ECDH_INIT 메시지를 서버에 전송 (클라이언트 공개키 전송)

  • 서버에서 SSH_MSG_KEX_ECDH_INIT 수신 시 비대칭키 키 쌍(임시) 생성
  • 서버는 클라이언트의 공개키와 자신의 키 쌍으로 대칭키 K 생성
  • 교환할 해시값 생성 (대칭키 포함, 서버의 개인키로 서명) 및 클라이언트로 전송  
    #  서명을 통해 올바른 서버임을 클라이언트가 확인 가능

  • 클라이언트는 서버로부터 SSH_MSG_KEX_ECDH_REPLY 수신 
  • 클라이언트가 서버의 응답으로부터 서버의 공개 키 추출, HS의 서명 확인
    # 로컬에 존재하는 서버 공개키와 추출한 공개키 비교, MITM 공격을 방지하기 위한 서명 확인
  • 클라이언트에서 대칭키 공유

  • 데이터 암호화를 시작하기 전 새로운 키 생성 (대칭키 K로 충분하지 않음)

 

공격자가 키 교환에 사용되는 개인키를 탈취할 수 있다는 믿음으로 암호화된 트래픽을 계속 저장하고 있어도, 개인키가 폐지되기 때문에 공격을 어렵게 만들 수 있다. (Foward Secrecy)

 


[자 료]

https://www.ssh.com/academy/ssh

https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process

https://goteleport.com/blog/ssh-handshake-explained/

https://assets.ctfassets.net/0lvk5dbamxpi/7wNRdbPyeUDql7sZjv3ZTp/ef86cf604b532728ee8da263d27883d8/RFC_4251_-_The_Secure_Shell__SSH__Protocol_Architecture