Có một tên dựa trên máy chủ ảo SSH đảo ngược proxy?


36

Tôi đã phát triển khá thích các proxy ngược HTTP trong môi trường phát triển của chúng tôi và thấy proxy ngược máy chủ ảo dựa trên DNS khá hữu ích. Chỉ có một cổng (và cổng chuẩn) mở trên tường lửa giúp quản lý dễ dàng hơn nhiều.

Tôi muốn tìm một cái gì đó tương tự để thực hiện các kết nối SSH nhưng không gặp nhiều may mắn. Tôi không muốn đơn giản sử dụng SSH đường hầm vì điều đó yêu cầu mở các phạm vi cổng khác với tiêu chuẩn. Có bất cứ điều gì ngoài đó có thể làm điều này?

HAProxy có thể làm điều này?


Là ứng dụng chuyển tập tin dự định của bạn, hoặc truy cập SSH thực tế vào máy chủ?
Kyle Hodgson

Truy cập SSH trực tiếp đến máy chủ lưu trữ là mục tiêu. Nhu cầu này xuất phát từ mong muốn chạy một máy chủ Mercurial trong nhà nhưng máy chủ của chúng tôi đứng sau tường lửa. Ngay bây giờ tôi đang làm việc chỉ đơn giản là thiết lập phiên bản HTTP nhưng tôi muốn có các cam kết sử dụng SSH thay vì HTTP. Truy cập SSH trực tiếp vào các máy chủ khác sẽ là một phần thưởng nếu điều này là có thể.
ahanson

Đây là một vấn đề gây phiền nhiễu.
thiên vị

Tôi hiểu rằng HAProxy hiện hỗ trợ điều này thông qua SNI. Mặc dù tôi chưa thể có được điều này.
Carel

Câu trả lời:


24

Tôi không tin SSH dựa trên tên là thứ gì đó sẽ có thể được cung cấp khi giao thức hoạt động.

Đây là một số lựa chọn.

  • Bạn có thể làm là thiết lập máy chủ trả lời cho cổng 22 để hoạt động như một cổng. Sau đó, bạn có thể định cấu hình máy chủ ssh để chuyển tiếp yêu cầu vào bên trong dựa trên khóa. Ví dụ SSH Gateway có khóa

  • Bạn có thể điều chỉnh ứng dụng khách của mình để sử dụng máy chủ đó làm proxy. Đó là, nó sẽ ssh đến máy chủ cổng, và sau đó sử dụng máy chủ đó để tạo kết nối đến máy chủ nội bộ. SSH proxy với cấu hình máy khách .

  • Bạn cũng có thể thiết lập một proxy http đơn giản ở cạnh. Sau đó sử dụng để cho phép kết nối đến. SSH thông qua proxy HTTP .

Rõ ràng với tất cả những điều trên, việc đảm bảo bạn cấu hình đúng và khóa cổng là khá quan trọng.


18

Tôi đã tìm kiếm một giải pháp cho vấn đề này trong và ngoài 16 tháng qua. Nhưng mỗi lần tôi nhìn, dường như không thể làm điều này với giao thức SSH như được chỉ định trong các RFC có liên quan và được triển khai bởi các triển khai chính.

Tuy nhiên, nếu bạn sẵn sàng sử dụng máy khách SSH được sửa đổi một chút và bạn sẵn sàng sử dụng các giao thức theo cách không được dự định chính xác khi chúng được thiết kế, thì có thể đạt được. Thêm về điều này dưới đây.

Tại sao nó không thể

Máy khách không gửi tên máy chủ như một phần của giao thức SSH.

Nó có thể gửi tên máy chủ như một phần của tra cứu DNS, nhưng có thể được lưu trong bộ nhớ cache và đường dẫn từ máy khách thông qua trình phân giải đến máy chủ có thẩm quyền có thể không vượt qua proxy và ngay cả khi nó không có cách nào mạnh mẽ để liên kết tra cứu DNS cụ thể với khách hàng SSH cụ thể.

Bạn cũng không thể làm gì với giao thức SSH. Bạn phải chọn một máy chủ mà không cần nhìn thấy biểu ngữ phiên bản SSH từ máy khách. Bạn phải gửi một biểu ngữ cho khách hàng, trước khi nó sẽ gửi bất cứ điều gì đến proxy. Các biểu ngữ từ các máy chủ có thể khác nhau và bạn không có cơ hội đoán, cái nào là đúng để sử dụng.

Mặc dù biểu ngữ này được gửi không được mã hóa, bạn không thể sửa đổi nó. Mỗi bit của biểu ngữ đó sẽ được xác minh trong quá trình thiết lập kết nối, do đó bạn sẽ gây ra lỗi kết nối một chút.

Kết luận với tôi là khá rõ ràng, người ta phải thay đổi một cái gì đó ở phía máy khách để làm cho kết nối này hoạt động.

Hầu hết các cách giải quyết đều gói gọn lưu lượng SSH bên trong một giao thức khác. Người ta cũng có thể tưởng tượng một sự bổ sung cho chính giao thức SSH, trong đó biểu ngữ phiên bản được gửi bởi máy khách bao gồm tên máy chủ. Điều này có thể vẫn tương thích với các máy chủ hiện có, vì một phần của biểu ngữ hiện được chỉ định là trường nhận dạng biểu mẫu miễn phí và mặc dù khách hàng thường đợi biểu ngữ phiên bản từ máy chủ trước khi gửi riêng, giao thức cho phép khách hàng gửi biểu ngữ của họ Đầu tiên. Một số phiên bản gần đây của ứng dụng khách ssh (ví dụ: phiên bản trên Ubuntu 14.04) sẽ gửi biểu ngữ mà không cần chờ biểu ngữ máy chủ.

Tôi không biết bất kỳ khách hàng nào đã thực hiện các bước để đưa tên máy chủ của máy chủ vào biểu ngữ này. Tôi đã gửi một bản vá vào danh sách gửi thư OpenSSH để thêm một tính năng như vậy. Nhưng nó đã bị từ chối dựa trên mong muốn không tiết lộ tên máy chủ cho bất kỳ ai rình mò lưu lượng SSH. Vì tên máy chủ bí mật về cơ bản không tương thích với hoạt động của proxy dựa trên tên, nên bạn sẽ không sớm thấy tiện ích mở rộng SNI chính thức cho giao thức SSH.

Một giải pháp thực sự

Giải pháp hiệu quả nhất với tôi là sử dụng IPv6.

Với IPv6 tôi có thể có một địa chỉ IP riêng được gán cho mỗi máy chủ, vì vậy cổng có thể sử dụng địa chỉ IP đích để tìm ra máy chủ nào sẽ gửi gói đến. Các máy khách SSH đôi khi có thể đang chạy trên các mạng nơi cách duy nhất để có địa chỉ IPv6 là sử dụng Teredo. Teredo được biết là không đáng tin cậy, nhưng chỉ khi kết thúc IPv6 gốc của kết nối đang sử dụng chuyển tiếp Teredo công khai. Người ta có thể chỉ cần đặt một rơle Teredo trên cổng, nơi bạn chạy proxy. Miredo có thể được cài đặt và cấu hình như một rơle trong vòng chưa đầy năm phút.

Một cách giải quyết

Bạn có thể sử dụng một máy chủ nhảy / máy chủ pháo đài. Cách tiếp cận này dành cho các trường hợp bạn không muốn tiếp xúc với cổng SSH của các máy chủ riêng lẻ với internet công cộng. Nó có thêm lợi ích trong việc giảm số lượng địa chỉ IP phải đối mặt bên ngoài mà bạn cần cho SSH, đó là lý do tại sao nó có thể sử dụng được trong kịch bản này. Thực tế đó là một giải pháp nhằm thêm một lớp bảo vệ khác vì lý do bảo mật không ngăn bạn sử dụng nó khi bạn không cần bảo mật bổ sung.

ssh -o ProxyCommand='ssh -W %h:%p user1@bastion' user2@target

Một cách bẩn để hack để làm cho nó hoạt động nếu giải pháp thực sự (IPv6) nằm ngoài tầm với của bạn

Bản hack mà tôi sắp mô tả chỉ nên được sử dụng như là phương sách cuối cùng. Trước khi bạn nghĩ đến việc sử dụng bản hack này, tôi thực sự khuyên bạn nên lấy địa chỉ IPv6 cho mỗi máy chủ mà bạn muốn có thể truy cập được bên ngoài thông qua SSH. Sử dụng IPv6 làm phương thức chính để truy cập các máy chủ SSH của bạn và chỉ sử dụng bản hack này khi bạn cần chạy máy khách SSH từ mạng chỉ có IPv4 nơi bạn không có bất kỳ ảnh hưởng nào đến việc triển khai IPv6.

Ý tưởng là lưu lượng giữa máy khách và máy chủ cần phải là lưu lượng SSH hoàn toàn hợp lệ. Nhưng proxy chỉ cần hiểu đủ về luồng gói để xác định tên máy chủ. Vì SSH không xác định cách gửi tên máy chủ, thay vào đó, bạn có thể xem xét các giao thức khác cung cấp khả năng như vậy.

Cả HTTP và HTTPS đều cho phép máy khách gửi tên máy chủ trước khi máy chủ gửi bất kỳ dữ liệu nào. Câu hỏi bây giờ là, liệu có thể xây dựng một luồng byte có hiệu lực đồng thời là lưu lượng SSH và là HTTP và HTTPS hay không. HTTP gần như không phải là khởi đầu, nhưng HTTP là có thể (đối với các định nghĩa đầy đủ tự do về HTTP).

SSH-2.0-OpenSSH_6.6.1 / HTTP/1.1
$: 
Host: example.com

Điều này trông giống như SSH hoặc HTTP đối với bạn? Đó là SSH và hoàn toàn tuân thủ RFC (ngoại trừ một số ký tự nhị phân được xử lý một chút bằng kết xuất SF).

Chuỗi phiên bản SSH bao gồm một trường nhận xét, ở trên có giá trị / HTTP/1.1. Sau khi SSH dòng mới có một số dữ liệu gói nhị phân. Gói đầu tiên là một MSG_SSH_IGNOREtin nhắn được gửi bởi máy khách và bị máy chủ bỏ qua. Tải trọng được bỏ qua là:

: 
Host: example.com

Nếu một proxy HTTP đủ tự do trong những gì nó chấp nhận, thì chuỗi byte tương tự sẽ được hiểu là một phương thức HTTP được gọi SSH-2.0-OpenSSH_6.6.1và dữ liệu nhị phân khi bắt đầu thông báo bỏ qua sẽ được hiểu là tên tiêu đề HTTP.

Proxy sẽ không hiểu phương thức HTTP hoặc tiêu đề đầu tiên. Nhưng nó có thể hiểu Hosttiêu đề, đó là tất cả những gì nó cần để tìm phần phụ trợ.

Để làm việc này, proxy phải được thiết kế theo nguyên tắc chỉ cần hiểu đủ HTTP để tìm phần phụ trợ, và khi đã tìm thấy phần phụ trợ, proxy sẽ chỉ truyền luồng byte thô và để lại kết thúc thực sự của kết nối HTTP sẽ được thực hiện bởi phụ trợ.

Nghe có vẻ hơi căng thẳng khi đưa ra rất nhiều giả định về proxy HTTP. Nhưng nếu bạn sẵn sàng cài đặt một phần mềm mới được phát triển với mục đích hỗ trợ SSH, thì các yêu cầu đối với proxy HTTP không có vẻ quá tệ.

Trong trường hợp của riêng tôi, tôi thấy phương thức này hoạt động trên một proxy đã được cài đặt mà không có thay đổi nào về mã, cấu hình, hay cách khác. Và đây là một proxy được viết chỉ có HTTP và không có SSH.

Bằng chứng về khái niệm khách hàngproxy . (Từ chối trách nhiệm rằng proxy là dịch vụ do tôi điều hành. Vui lòng thay thế liên kết một khi bất kỳ proxy nào khác đã được xác nhận để hỗ trợ việc sử dụng này.)

Hãy cẩn thận với hack này

  • Đừng sử dụng nó. Tốt hơn hết là sử dụng giải pháp thực sự, đó là IPv6.
  • Nếu proxy cố gắng hiểu lưu lượng HTTP, nó chắc chắn sẽ bị hỏng.
  • Dựa vào một máy khách SSH đã sửa đổi là không tốt.

Bạn có thể giải thích những gì bạn muốn nói the gateway can use the destination IP address to find out which server to send the packet totrong giải pháp IPv6 không?
Jacob Ford

@JacobFord Chìa khóa để hiểu câu đó là tôi sử dụng cổng từ không phải proxy . Với IPv6, bạn có đủ địa chỉ IP để gán một cho mọi máy chủ và vẫn có địa chỉ dự phòng. Tất cả các máy bạn đặt sau proxy sẽ có địa chỉ IP của riêng chúng, đó là những gì bạn có tên giải quyết. Vì vậy, bạn không còn cần proxy, khách hàng gửi lưu lượng truy cập của họ đến địa chỉ IP của máy chủ mong muốn và bạn có thể định tuyến lưu lượng truy cập trực tiếp đến đó.
kasperd

đối với phần giải pháp, có một công tắc lệnh tương đối mới cho ssh -J, vì vậy bạn có thể sử dụng: ssh -J user1 @ front user2 @ target
PMN

3

Tôi không tin đây là điều có thể xảy ra, ít nhất là theo cách bạn mô tả, mặc dù tôi rất muốn được chứng minh là sai. Không có vẻ như khách hàng gửi tên máy chủ mà nó muốn kết nối (ít nhất là rõ ràng). Bước đầu tiên của kết nối SSH dường như là thiết lập mã hóa.

Ngoài ra, bạn sẽ gặp vấn đề với xác minh khóa máy chủ. Các máy khách SSH sẽ xác minh các khóa dựa trên địa chỉ IP cũng như tên máy chủ. Bạn sẽ có nhiều tên máy chủ lưu trữ với các khóa khác nhau, nhưng cùng một IP bạn đang kết nối.

Một giải pháp khả thi là có một máy chủ 'pháo đài', trong đó khách hàng có thể ssh vào máy đó, lấy vỏ bình thường (hoặc bị hạn chế nếu muốn) và sau đó có thể ssh vào máy chủ nội bộ từ đó.


Khái niệm pháo đài là những gì chúng tôi hiện đang thiết lập nhưng có vấn đề đối với việc kiểm soát phiên bản của tôi (mà không cần nỗ lực thêm).
ahanson

Thật khó chịu khi ssh không gửi fqdn và xử lý DNS ở phía máy khách. Tôi đoán mọi người đã không lo lắng về sự phình to của IP công cộng và NAT khi hầu hết các giao thức cấp ứng dụng TCP / IP được tạo. Bởi vì, nghiêm túc, bạn sẽ có thể thực hiện NAT dựa trên FQDN với iptables (tức là bộ lọc kernel).
thiên vị

Các hostkey có thể là chìa khóa của proxy ngược. Đây là một lợi ích nếu bạn tin tưởng vào bảo mật của phụ trợ, vì bạn có quyền kiểm soát mạng nội bộ và máy chủ lưu trữ.
rox0r

@bias Bạn không thể thực hiện NAT dựa trên tên máy chủ, ngay cả khi giao thức cấp cao hơn gửi tên máy chủ. Lý do không thể thực hiện được là, việc lựa chọn phụ trợ phải được thực hiện khi nhận được gói SYN, nhưng tên máy chủ chỉ được gửi sau khi SYN đã được xử lý và trả về SYN-ACK. Tuy nhiên, bạn có thể sử dụng proxy lớp ứng dụng rất mỏng cho các giao thức gửi tên máy chủ, chẳng hạn như http và https.
kasperd

3

Có một đứa trẻ mới vào khối. SSH piper sẽ định tuyến kết nối của bạn dựa trên tên người dùng được xác định trước, nên được ánh xạ tới các máy chủ bên trong. Đây là giải pháp tốt nhất trong bối cảnh proxy ngược.

Súng bắn tỉa SSh trên github

Các thử nghiệm đầu tiên của tôi đã xác nhận, cả SSH và SFTP đều hoạt động.


Đó thực sự là một cuộc tấn công MITM. Tôi hy vọng nó sẽ phá vỡ mọi thiết lập được bảo vệ chống lại các cuộc tấn công của MITM.
kasperd

1
Trên thực tế, bên lưu trữ là cả hai, chủ nhà và người đàn ông ở giữa, do đó chỉ có hai người đó tham gia.
Király István

@ KirályIstván đây là dự án tuyệt vời và bằng chứng là các câu trả lời khác không chính xác 100%. Tôi đã tạo công cụ tương tự dựa trên github.com/gliderlabs/sshfront và một số bash / python (Tôi không thể mở nguồn nhưng nó không thú vị - bash chạy ssh client và python được sử dụng làm trình xử lý auth). Nhưng tôi có một vấn đề với giải pháp hiện tại. Nó không hỗ trợ sftp (scp works). Nó treo cố gắng để chạy hệ thống con debug1: Sending subsystem: sftp. Hóa ra áo phía trước không hỗ trợ các hệ thống con. Bạn có hỗ trợ hem trong SSh piper?
Maciek Sawicki

1
@MaciekSawicki Tôi không phải là tác giả. Tôi chỉ sử dụng nó trong dự án của tôi. .)
Király István

2

Tôi tự hỏi nếu Honeytrap (honeypot tương tác thấp) có chế độ proxy không thể được sửa đổi để đạt được điều đó.

Honeypot này có thể chuyển tiếp bất kỳ giao thức nào sang máy tính khác. Thêm một hệ thống vhost dựa trên tên (do Apache triển khai) có thể làm cho nó trở thành một proxy ngược hoàn hảo cho bất kỳ giao thức nào không?

Tôi không có kỹ năng để đạt được điều đó nhưng có lẽ đó có thể là một dự án tuyệt vời.


ý tưởng tuyệt vời!
thiên vị

1
Tính năng vhost trong Apache phụ thuộc vào máy khách gửi tên máy chủ trước khi bất kỳ dữ liệu nào được gửi từ máy chủ. Giao thức SSH không liên quan đến tên máy chủ như vậy, vì vậy tôi không thấy cách bạn thậm chí bắt đầu triển khai một tính năng như vậy. Nhưng nếu bạn có thể giải thích các ý tưởng của mình, tôi sẽ vui lòng thực hiện bằng chứng về khái niệm hoặc cho bạn biết, tại sao nó không hiệu quả.
kasperd

1

Khi số lượng cổng / máy chủ bạn muốn truy cập đằng sau tường lửa tăng lên, sự tiện lợi của VPN sẽ tăng lên.

Tôi không thích VPN, mặc dù.


1

bởi vì cách làm việc của ssh tôi nghĩ rằng nó không thể. Tương tự như https, bạn sẽ phải có các IP (bên ngoài) khác nhau cho các máy chủ khác nhau, vì cổng không biết bạn muốn kết nối ở đâu vì mọi thứ trong ssh đều được mã hóa

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.