개발 환경에서 HTTP 리버스 프록시를 좋아했으며 DNS 기반 가상 호스트 리버스 프록시가 매우 유용하다는 것을 알았습니다. 방화벽에서 하나의 포트 (및 표준 포트) 만 열면 관리가 훨씬 쉬워집니다.
SSH 연결과 비슷한 것을 찾고 싶지만 많은 운이 없었습니다. SSH 터널링을 사용하지 않는 것이 좋습니다. 표준 이외의 포트 범위를 열어야하기 때문입니다. 이것을 할 수있는 것이 있습니까?
HAProxy가이를 수행 할 수 있습니까?
개발 환경에서 HTTP 리버스 프록시를 좋아했으며 DNS 기반 가상 호스트 리버스 프록시가 매우 유용하다는 것을 알았습니다. 방화벽에서 하나의 포트 (및 표준 포트) 만 열면 관리가 훨씬 쉬워집니다.
SSH 연결과 비슷한 것을 찾고 싶지만 많은 운이 없었습니다. SSH 터널링을 사용하지 않는 것이 좋습니다. 표준 이외의 포트 범위를 열어야하기 때문입니다. 이것을 할 수있는 것이 있습니까?
HAProxy가이를 수행 할 수 있습니까?
답변:
이름 기반 SSH가 프로토콜의 작동 방식에 따라 가능하다고 생각하지 않습니다.
몇 가지 대안이 있습니다.
포트 22가 게이트웨이 역할을하도록 응답하는 호스트를 설정하면됩니다. 그런 다음 키를 기반으로 요청을 내부로 전달하도록 ssh 서버를 구성 할 수 있습니다. 키가있는 SSH 게이트웨이 예
해당 호스트를 프록시로 사용하도록 클라이언트를 조정할 수 있습니다. 즉, 게이트웨이 호스트에 ssh 한 다음 해당 호스트를 사용하여 내부 호스트에 연결합니다. 클라이언트 구성의 SSH 프록시 .
가장자리에 간단한 http 프록시를 설정할 수도 있습니다. 그런 다음이를 사용하여 들어오는 연결을 허용하십시오. HTTP 프록시 를 통한 SSH .
분명히 위의 모든 사항과 함께 게이트웨이를 올바르게 구성하고 잠그는 것이 매우 중요합니다.
지난 16 개월 동안이 문제에 대한 해결책을 찾고있었습니다. 그러나 내가 볼 때마다 관련 RFC에 지정되고 주요 구현으로 구현 된 SSH 프로토콜 로이 작업을 수행하는 것이 불가능한 것 같습니다.
그러나 약간 수정 된 SSH 클라이언트를 사용하고 의도 한대로 의도하지 않은 방식으로 프로토콜을 사용하려는 경우 달성 할 수 있습니다. 이에 대한 자세한 내용은 아래를 참조하십시오.
불가능한 이유
클라이언트는 SSH 프로토콜의 일부로 호스트 이름을 보내지 않습니다.
호스트는 DNS 조회의 일부로 호스트 이름을 보낼 수 있지만 캐시 될 수 있으며 클라이언트에서 리졸버를 통해 권한있는 서버로의 경로가 프록시를 통과하지 못할 수 있으며 특정 DNS 조회를 특정 SSH 클라이언트.
SSH 프로토콜 자체로 할 수있는 일은 없습니다. 클라이언트에서 SSH 버전 배너를 보지 않아도 서버를 선택해야합니다. 프록시로 무언가를 보내기 전에 클라이언트에게 배너를 보내야합니다. 서버의 배너는 다를 수 있으며 어떤 배너를 사용해야할지 추측 할 기회가 없습니다.
이 배너는 암호화되지 않은 상태로 보내지더라도 수정할 수 없습니다. 연결 설정 중에 해당 배너의 모든 비트가 확인되므로 연결이 약간 끊어 질 수 있습니다.
나에게 결론은 분명하다.이 연결을 작동시키기 위해서는 클라이언트 측에서 무언가를 변경해야한다.
대부분의 해결 방법은 SSH 트래픽을 다른 프로토콜로 캡슐화합니다. 클라이언트가 보낸 버전 배너가 호스트 이름을 포함하는 SSH 프로토콜 자체에 추가 된 것을 상상할 수도 있습니다. 배너의 일부가 현재 자유 형식 식별 필드로 지정되어 있기 때문에 기존 서버와의 호환성을 유지할 수 있으며 클라이언트는 일반적으로 서버에서 버전 배너를 기다리기 전에 자체적으로 배너를 보내지 만 프로토콜은 클라이언트가 배너를 보낼 수 있도록합니다. 먼저. ssh 클라이언트의 일부 최신 버전 (예 : Ubuntu 14.04의 버전)은 서버 배너를 기다리지 않고 배너를 보냅니다.
이 배너에 서버의 호스트 이름을 포함시키기위한 조치를 취한 클라이언트를 모르겠습니다. 그러한 기능을 추가 하기 위해 OpenSSH 메일 링리스트 에 패치 를 보냈 습니다 . 그러나 SSH 트래픽을 스누핑하는 사람에게 호스트 이름을 공개하지 않으려는 의도로 거부되었습니다. 비밀 호스트 이름은 기본적으로 이름 기반 프록시의 작동과 호환되지 않으므로 언제든지 SSH 프로토콜에 대한 공식 SNI 확장을 기대하지 마십시오.
실제 솔루션
나에게 가장 효과적인 솔루션은 실제로 IPv6을 사용하는 것이 었습니다.
IPv6을 사용하면 각 서버에 별도의 IP 주소를 할당 할 수 있으므로 게이트웨이는 대상 IP 주소를 사용하여 패킷을 보낼 서버를 찾을 수 있습니다. SSH 클라이언트는 때때로 Teredo를 사용하여 IPv6 주소를 얻는 유일한 방법 인 네트워크에서 실행될 수 있습니다. Teredo는 신뢰할 수없는 것으로 알려져 있지만 연결의 기본 IPv6 끝이 공용 Teredo 릴레이를 사용하는 경우에만 가능합니다. 게이트웨이에 Teredo 릴레이를 배치하면 프록시를 실행할 수 있습니다. Miredo는 5 분 이내에 릴레이로 설치 및 구성 할 수 있습니다.
해결 방법
점프 호스트 / bastion 호스트를 사용할 수 있습니다. 이 방법은 개별 서버의 SSH 포트를 공용 인터넷에 직접 노출시키지 않으려는 경우에 사용됩니다. SSH에 필요한 외부 용 IP 주소 수를 줄이는 데 추가 이점이 있으므로이 시나리오에서 사용할 수 있습니다. 보안상의 이유로 다른 보호 계층을 추가하기위한 솔루션이라는 사실은 추가 보안이 필요하지 않을 때이를 사용하지 못하게하지 않습니다.
ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target
실제 솔루션 (IPv6)이 접근 할 수없는 경우 해킹하기가 더럽습니다.
내가 설명하려는 핵은 절대적으로 최후의 수단으로 만 사용해야합니다. 이 핵 사용에 대해 생각하기 전에 SSH를 통해 외부에 도달하려는 각 서버에 대해 IPv6 주소를 얻는 것이 좋습니다. SSH 서버에 액세스하기위한 기본 방법으로 IPv6을 사용하고 IPv6 배포에 영향을 미치지 않는 IPv4 전용 네트워크에서 SSH 클라이언트를 실행해야하는 경우에만이 핵을 사용하십시오.
아이디어는 클라이언트와 서버 간의 트래픽이 완벽하게 유효한 SSH 트래픽이어야한다는 것입니다. 그러나 프록시는 호스트 이름을 식별하기 위해 패킷 스트림에 대해 충분히 이해하면됩니다. SSH는 호스트 이름을 보내는 방법을 정의하지 않기 때문에 이러한 가능성을 제공하는 다른 프로토콜을 고려할 수 있습니다.
HTTP와 HTTPS는 모두 서버가 데이터를 보내기 전에 클라이언트가 호스트 이름을 보낼 수있게합니다. 이제 문제는 SSH 트래픽과 HTTP 및 HTTPS로 동시에 유효한 바이트 스트림을 구성 할 수 있는지 여부입니다. HTTPs 그것은 거의 초보자가 아니지만 HTTP가 가능합니다 (HTTP의 충분히 자유로운 정의를 위해).
SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$:
Host: example.com
이것은 SSH 또는 HTTP처럼 보입니까? SSH이며 완벽하게 RFC를 준수합니다 (이진 문자 중 일부는 SF 렌더링으로 약간 엉망이 된 것 제외).
SSH 버전 문자열에는 주석 필드가 포함되며, 위의 값은 / HTTP/1.1
입니다. 개행 후 SSH에는 일부 바이너리 패킷 데이터가 있습니다. 첫 번째 패킷은 MSG_SSH_IGNORE
클라이언트가 보낸 메시지이며 서버는 무시합니다. 무시할 페이로드는 다음과 같습니다.
:
Host: example.com
HTTP 프록시가 받아들이는 것에 대해 충분히 자유롭다면, 동일한 바이트 시퀀스가 HTTP 메소드라고 부르고 SSH-2.0-OpenSSH_6.6.1
무시 메시지 시작시의 이진 데이터는 HTTP 헤더 이름으로 해석됩니다.
프록시는 HTTP 메소드 나 첫 번째 헤더를 모두 이해하지 못합니다. 그러나 Host
백엔드를 찾기 위해 필요한 모든 헤더를 이해할 수 있습니다.
이것이 작동하려면 프록시는 백엔드를 찾기에 충분한 HTTP 만 이해하면된다는 원칙에 따라 설계되어야하고 일단 백엔드가 발견되면 프록시는 단순히 원시 바이트 스트림을 전달하고 실제 종료 상태를 유지합니다. 백엔드가 수행 할 HTTP 연결
HTTP 프록시에 대해 너무 많은 가정을하기에는 약간의 스트레칭처럼 들릴 수 있습니다. 그러나 SSH를 지원할 목적으로 개발 된 새로운 소프트웨어를 기꺼이 설치하려는 경우 HTTP 프록시에 대한 요구 사항이 나쁘게 들리지 않습니다.
내 경우에는이 방법이 코드, 구성 등을 변경하지 않고 이미 설치된 프록시에서 작동하는 것으로 나타났습니다. 그리고 이것은 SSH 만 염두에두고 HTTP만으로 작성된 프록시를위한 것입니다.
개념 증명 클라이언트 및 프록시 . (프록시는 저에 의해 운영되는 서비스라는 면책 사항입니다. 다른 프록시가이 사용법을 지원한다고 확인되면 링크를 자유롭게 교체하십시오.)
이 핵의주의 사항
the gateway can use the destination IP address to find out which server to send the packet to
IPv6 솔루션에서의 의미를 자세히 설명 할 수 있습니까 ?
-J
에 대한 비교적 새로운 명령 스위치가 있으므로 다음을 사용할 수 있습니다. ssh -J user1 @ front user2 @ target
나는 이것이 틀렸다는 것을 증명 하기는하지만 적어도 당신이 묘사 한 방식으로 가능할 것이라고 믿지 않습니다. 클라이언트가 연결하고자하는 호스트 이름을 (최소한 명확하게) 보내는 것으로 보이지 않습니다. SSH 연결의 첫 단계는 암호화를 설정하는 것 같습니다.
또한 호스트 키 확인에 문제가 있습니다. SSH 클라이언트는 호스트 이름뿐만 아니라 IP 주소를 기반으로 키를 확인합니다. 다른 키를 가진 여러 호스트 이름이 있지만 연결하는 동일한 IP가 있습니다.
가능한 해결책은 'bastion'호스트를 사용하는 것인데, 여기서 클라이언트는 해당 시스템에 ssh in하고 정상적인 (또는 원하는 경우 제한됨) 쉘을 가져온 다음 내부 호스트로 ssh 할 수 있습니다.
블록에 새로운 아이가 있습니다. SSH 파이퍼는 내부 호스트에 맵핑되어야하는 사전 정의 된 사용자 이름을 기반으로 연결을 라우팅합니다. 리버스 프록시와 관련하여 최상의 솔루션입니다.
첫 번째 테스트에서 SSH와 SFTP는 모두 작동합니다.
debug1: Sending subsystem: sftp
됩니다. shirt-front는 하위 시스템을 지원하지 않습니다. SSh 파이퍼에서 밑단을지지합니까?
프록시 모드가있는 Honeytrap (낮은 상호 작용 허니팟)이 그것을 달성하기 위해 수정할 수 있는지 궁금합니다.
이 허니팟은 모든 프로토콜을 다른 컴퓨터로 전달할 수 있습니다. 이름 기반 vhost 시스템을 추가하면 (Apache로 구현 됨) 모든 프로토콜에 대해 완벽한 역방향 프록시가 될 수 있습니다.
나는 그것을 달성 할 수있는 기술이 없지만 어쩌면 훌륭한 프로젝트 일 수 있습니다.