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_IGNORE
tin 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.1
và 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 Host
tiê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àng và proxy . (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.