Rails应用程序中的代理Websocket请求



我有一个rails应用程序和一个Golang服务。Rails应用程序是一个面向用户的UI应用程序。来自前端的部分请求被路由到golang服务以获得某些功能。到目前为止,我们只有来自UI的HTTP请求。

现在我们在UI中有了websockets功能。因此,我们需要通过Rails应用程序将这些websocket请求路由到Golang服务。基本上,Rails应用程序控制身份验证/授权部分。因此,我们需要通过Rails应用程序来路由请求。

我们探索https://github.com/ncr/rack-proxy路由请求,但我们无法正确路由websocket请求。我们尝试了以下代码,其中在ws://localhost:3000/ws/v1/stat上接收web套接字请求,并使用以下代码将其发送到ws-//localhost:4000/ws/v1/stats

# frozen_string_literal: true
require 'rack-proxy'
module Proxy
ENV['SERVICE_URL'] ||= 'http://guides.rubyonrails.org'
class GoServiceProxy < Rack::Proxy
def perform_request(env)
request = Rack::Request.new(env)
# use rack proxy for anything hitting our host app at /example_service
# if request.path =~ %r{^/example_service}
if request.path =~ %r{stats}
backend = URI(ENV['SERVICE_URL'])
# most backends required host set properly, but rack-proxy doesn't set this for you automatically
# even when a backend host is passed in via the options
env["HTTP_HOST"] = 'localhost:4000'
# This is the only path that needs to be set currently on Rails 5 & greater
#env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
# don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
env['HTTP_COOKIE'] = ''
super(env)
else
@app.call(env)
end
end
end
end

但是,当我在ws://localhost:3000/ws/v1/stat上卷曲时,我得到101响应,但从go服务发送的消息没有到来。下面的截图是我得到的回应:

curl -v --request GET 'http://localhost:3000/ws/v1/stats' 
--header 'Content-Type: application/json' 
--header 'Upgrade: websocket' 
--header 'Connection: upgrade' 
--header 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==' 
--header 'Sec-Websocket-Version: 13'
Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 3000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /ws/v1/stats HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: application/json
> Upgrade: websocket
> Connection: upgrade
> Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
> Sec-Websocket-Version: 13
>
< HTTP/1.1 101 Switching Protocols
< sec-websocket-accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
< Cache-Control: no-cache
< X-Request-Id: 957758f9-d762-43d0-bffb-fdd72efbfbc1
< X-Runtime: 0.002848
<
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

有什么方法可以通过Rails应用程序代理websocket请求吗?

这听起来像是A/B问题。

真正的问题是使用Rails凭据在Go应用程序上验证WebSocket用户。

为什么不代理连接

您的最新解决方案似乎是让Rails对用户进行身份验证,然后将连接代理到Go应用程序。

此解决方案有许多安全问题,同时也会带来很大的性能损失。例如:

  1. (安全(Go应用程序假定所有连接都是";"安全";,通过让攻击者尝试直接或通过不同的路由(绕过Rails应用程序(连接到该服务,使其成为网络攻击的方便载体。

  2. (性能(所有的网络流量和连接都增加了一倍(实际上,如果不超过一倍的话(,这给Rails应用程序带来了更高的负载。

更好的解决方案

一个更好的解决方案是编写一个小型Rails AUTH应用程序,为Go应用程序提供身份验证服务。

Go应用程序执行身份验证。假设任何网络流量都是安全的(即使是看起来是本地的流量(也会导致灾难。

这些身份验证服务可能会测试通过Rails面向用户的应用程序预先协商的长期身份验证令牌(较差的安全性(或一次性身份验证令牌。

WebSocket连接将直接连接到Go应用程序(很可能使用子域或URL路由(,并使用身份验证微服务进行验证。

祝你好运!

最新更新