SSH 프로토콜
폐쇄망 시스템에 접근하여 어플리케이션을 인스턴스에 배포하기 위한 목적의 어플리케이션을 개발하며 사용한 SSH 프로토콜을 사용한 경험을 기반으로 작성함. 기존에는 파일질라와 같은 프로그램을 사용하여 어플리케이션을 업로드 한 다음, linux 명령어로…
SSH 프로토콜
폐쇄망 시스템에 접근하여 어플리케이션을 인스턴스에 배포하기 위한 목적의 어플리케이션을 개발하며 사용한 SSH 프로토콜을 사용한 경험을 기반으로 작성함. 기존에는 파일질라와 같은 프로그램을 사용하여 어플리케이션을 업로드 한 다음, linux 명령어로 파일 권한부여 및 설정 파일 변경을 진행했는데, 이를 버튼기반 UI 프로그램을 구현하여 프로세스를 간소화함.
사용한 libssh2 라이브러리는 cmake로 .lib, .h 만들었고, 그때 만든 파일은 github에 저장함.
AWS의 EC2에 접속을 하거나, remote PC로 접속을 하거나, CI/CD 파이프라인에서 데이터를 전송하는 등 생각보다 많은 솔루션에서 SSH를 사용한다. 통신 과정에서 보안이슈로 인해 등장한 프로토콜이다.
java / javascript /python과 같은 언어에서는 기본 라이브러리에 ssh 프로토콜이 구현된 클래스와 메서드가 있어서 손쉽게 사용이 가능하지만, arm-linux 환경에서 구동되는 C 프로그램들을 libssh2와 같은 외부 라이브러리를 추가해서 필요한 로직을 구현했었다.
업무에서 구현하고 만들어진 예제를 기반으로 코드를 짤 때는 바빠서 notion에 대충 정리를 했는데, 많이 쓰이는 개념이므로 한번 정리를 해둔다.
ssh Protocol의 표준문서는 RFC4250이다. 그리고 아래 표준 문서도 같이 참고를 해야 된다.

SSH란?
Secure Shell의 약자로서 TCP 보안 채널(터널링)을 형성하여 그 위에서 기타 응용 프로토콜들이 안전하게 데이터를 교환하도록 하는 응용 프로그램 혹은 프로토콜을 말한다.

TCP 보안 채널(터널링)은 보통 아래와 같이 형성이 된다. 그리고 기본적으로 22번 포트를 사용한다. 명령어 옵션을 통해서 22번 외 포트도 사용은 가능하다.
http://www.ktword.co.kr/test/view/view.php?m_temp1=2524
그리고 SSH는 이름 그대로 shell에 접근을 하는 방식이다.
위 내용들을 7 layer에 대입시켜서 상세하게 그려보면 아래와 같다.

각 계층별로 데이터가 돌아다닐 때 SSH 프로토콜의 패킷 형식은 아래와 같다.
http://www.ktword.co.kr/test/view/view.php?m_temp1=2524
- Length는 type ~ crc까지의 길이다.
- padding은 1–8 바이트를 추가하는 영역이다. 보안 목적
- type은 ssh 프로토콜 패킷임을 나타낸다
- 데이터는 실제 운반되는 데이터이다
- CRC는 오류 검출을 위해 특정 함수로 만들어지는 값이다. 4B이므로 보통 crc32를 사용한다는 의미.
SSH 동작원리
동작원리는 링크의 블로그에서 설명을 아주 잘 해주셨다. 링크의 블로그에서 ‘SSH Academy’라는 사이트를 알게 되었는데 여기 설명이 잘 되어있다.

https://www.ssh.com/academy/ssh/protocol
1단계 — 클라이언트는 서버에 접속하기 위해서 22 port TCP 접속을 한다.
2단계 — 서버는 자신의 Host Key를 클라이언트에게 전송한다.
3단계 — 키 교환 과정을 거쳐서 클라이언트와 서버가 채널을 오픈한다.
4단계 — 사용자가 서버 운영 시스템에 로그인하여 접속한다.
키 교환과정에서 SSH 프로토콜이 사용하는 Key값은 아래와 같다.
- host key : 공개 키
- session key : 서버 및 클라이언트가 negotiate하여 서로 공유하게되는 대칭 키
2단계에서 서버는 최초 접속한 클라이언트에게 공개키를 전달한다. 클라이언트는 차후 비교를 위해서 ~/.ssh/know_hosts에 저장한다.
클라이언트는 해당 키 값을 통해서 아래 절차를 거쳐서 올바른 서버인지 확인을 한다.
- 클라이언트에서 난수 생성, 난수 해시값 생성 및 저장
- 난수를 서버의 공개키로 암호화 후 서버에 전송
- 서버에서 서버의 개인키로 데이터를 복호화하여 난수 추출
- 서버에서 복호화된 난수 해시값을 생성 후 클라이언트에게 전송
- 클라이언트에 저장된 난수 해시값과 서버에서 받은 난수 해시값을 비교
- 동일할 시 올바른 서버 확인
3단계 negotiate 과정에서는 디피-헬만 알고리즘을 통해서 안전하게 대칭키를 공유한다. 이 알고리즘은 상대방의 공개키와 나의 개인키를 통해 대칭키를 추출하는 방식이다. 이 때 교환되는 키 쌍은 2단계의 키 쌍과는 다르다.
4단계에서 가장 간단한 방식은 패스워드 인증이지만, 권장하는 방식은 SSH 키 쌍을 사용하는 것이다. 절차는 아래와 같다.
- 클라이언트는 인증할 키 쌍의 ID를 서버에 전송
- 서버는 클라이언트가 접속하고자 하는 계정의 .ssh/authorized_keys 파일을 확인
- ID에 매칭되는 공개키가 있을 시, 서버는 난수를 생성하고 클라이언트의 공개키로 암호화
- 서버는 클라이언트에게 암호화된 메시지 전송
- 클라이언트의 개인키를 통해 암호화된 메시지를 복호화하여 난수 추출
- 클라이언트는 난수를 세션키와 결합하여 해시값 계산 후 서버 전송
- 서버는 저장된 난수와 세션키를 결합하여 해시값 계산 후 비교
- 일치할 시 클라이언트 인증
4단계 이후 클라이언트는 자신의 공개키를 서버의 authorized_keys 파일에 등록한다. 공개키는 ssh-keygen 명령어로 생성한다. id_ras.pub 혹은 id_rsa를 생성한다.
복잡한 과정이지만 알아두면 AWS EC2를 접속할 때 왜 /.ssh에서 host 정보를 등록하고 ssh 접속을 하는지, 혹은 teraterm이나 상용 프로그램에서 로그인 방식이 여러가지가 있는지, 왜 이런 명령어를 사용하는지 등등을 알 수 있다.
코드로 보는 ssh 접속
c언어로 작성 된 libssh2 오픈소스 예제 코드이다. main함수만 가져왔는데, 함수명을 대충 보면서 따라가면서 이해가 된다면 위 내용이 어느정도 이해가 되었다고 보면 되겠다.
[embed]
ssh 명령어 사용법
보통 유닉스나 리눅스는 OpenSsh가 내장되어 있는 경우가 많다. ssh -help 명령어를 입력하면 아래와 같이 옵션을 확인 할 수 있다.

자주 썻던 옵션은 p 옵션인데 특정 포트를 지정할 수 있다. 꼭 22번이 아니어도 된다는 것!
키 생성과 키 삭제 관련된 명령어도 정말 많이 쓰는 듯하다. AWS에서 EC2 접속 방식을 바꾸게 되면 key값이 바뀌기 때문에 새로 생성해주어야 한다.
라즈베리파이 등 다양한 타겟보드에서 사용할 때도 마찬가지이다.

명령어는 ssh-keygen 인데 키 삭제는 ssh-keygen -R <IP>이다.
마무리
진짜 많이 쓰이는 개념이라서 기본적으로 요정도만 알아도 실무에서 다양한 툴들을 사용함에 문제가 없는듯하다. ( 이런말 함부로 쓰면 안되는데… 나중에 문제되는 것은 아닐지…)
메타데이터
- post_id
- f4079b1103ab
- slug
- ssh-프로토콜-f4079b1103ab
- url
- https://medium.com/@tas.com/ssh-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-f4079b1103ab
- canonical_url
- https://medium.com/@tas.com/ssh-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-f4079b1103ab
- author_url
- https://medium.com/@tas.com
- status
- ok
- fetched_at
- 2026-06-29 22:44:20