使用Cro实现安全的WebSockets

10

简述:我使用Cro和websocket在互联网服务器上创建了一个服务。使用Cro示例非常简单。当页面作为localhost提供服务时,从HTML页面发送和接收数据没有问题。但是当页面使用https提供服务时,无法建立websocket连接。 如何使用Cro使用wss协议?

更新:安装cro并运行cro stub :secure后,service.p6文件中有一些文档中未明确说明的代码。

更多细节: 我有一个在互联网服务器上运行的docker文件,Cro设置为监听35145端口,因此docker命令为docker --rm -t myApp -p 35145:35145

服务文件包含以下内容:

use Cro::HTTP::Log::File;
use Cro::HTTP::Server;
use Cro::HTTP::Router;
use Cro::HTTP::Router::WebSocket;

my $host = %*ENV<RAKU_WEB_REPL_HOST> // '0.0.0.0';
my $port = %*ENV<RAKU_WEB_REPL_PORT> // 35145;
my Cro::Service $http = Cro::HTTP::Server.new(
    http => <1.1>,
    :$host,
    :$port,
    application => routes(),
    after => [
        Cro::HTTP::Log::File.new(logs => $*OUT, errors => $*ERR)
    ]
    );
$http.start;
react {
    whenever signal(SIGINT) {
        say "Shutting down...";
        $http.stop;
        done;
    }
}
sub routes() {
    route {
        get -> 'raku' {
            web-socket :json, -> $incoming {
                supply whenever $incoming -> $message {
                    my $json = await $message.body;
                    if $json<code> {
                        my $stdout, $stderr;
                        # process code 
                        emit({ :$stdout, :$stderr })
                    }
                }
            }
        }
    }
}

在HTML中,我有一个带有id raku-code 的文本区域容器。js脚本在DOM准备就绪后触发的处理程序中具有以下内容(我在脚本的其他位置设置了websocketHost和websocketPort):
const connect = function() {
    // Return a promise, which will wait for the socket to open
    return new Promise((resolve, reject) => {
        // This calculates the link to the websocket.
        const socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:');
        const socketUrl = `${socketProtocol}//${websocketHost}:${websocketPort}/raku`;
        socket = new WebSocket(socketUrl);

        // This will fire once the socket opens
        socket.onopen = (e) => {
            // Send a little test data, which we can use on the server if we want
            socket.send(JSON.stringify({ "loaded" : true }));
            // Resolve the promise - we are connected
            resolve();
        }

        // This will fire when the server sends the user a message
        socket.onmessage = (data) => {
            let parsedData = JSON.parse(data.data);
            const resOut = document.getElementById('raku-ws-stdout');
            const resErr = document.getElementById('raku-ws-stderr');
            resOut.textContent = parsedData.stdout;
            resErr.textContent = parsedData.stderr;
        }

设置了此JS脚本的HTML文件并在本地提供服务时,我可以将数据发送到在互联网服务器上运行的Cro应用程序,并且Cro应用程序(在docker映像中运行)处理并返回放置在正确的HTML容器中的数据。使用Firefox和开发人员工具,我可以看到ws连接已创建。

但是,当我通过强制访问https来通过Apache提供相同的文件时,Firefox发出错误,表示无法创建'wss'连接。此外,如果我在JS脚本中强制执行“ws”连接,则Firefox会阻止创建非安全连接。

a) 如何更改Cro编码以允许使用wss?从Cro文档中看来,我需要添加一个Cro :: TLS侦听器,但不清楚在哪里实例化侦听器。 b) 如果要将其放在Docker文件中,我是否需要在映像中包含秘密加密密钥,这不是我想做的事情吗? c) 是否有一种方式将Cro应用程序放在Apache服务器后面,以便由Apache解密/加密websocket?

2个回答

5
如何更改Cro编码以允许wss?从Cro文档中看来,我需要添加一个Cro::TLS监听器,但不清楚在哪里实例化监听器。
只需将所需参数传递给Cro::HTTP::Server,它将为您设置监听器。
如果这是在docker文件中,我需要在镜像中包含秘密加密密钥吗?这不是我想做的事情。
不需要。您可以将它们保存在卷中,或者从主机机器上绑定它们。
有没有办法将Cro应用程序放在Apache服务器后面,以便websocket由Apache解密/加密?

是的,与任何其他应用程序一样。使用mod_proxymod_proxy_wstunnelProxyPass命令。其他前端,如nginx、haproxy或envoy也可以完成此任务。


我使用的方法是反向代理。wss被代理到http和ws,并更改了端口。因此,加密/解密由Apache完成,而不是Cro。按照这里描述的方式,Cro也可以执行此操作,但我决定将加密/解密和应用程序分开放置在docker中。 - Richard Hainsworth

2

虽然这不是一个纯粹的CRO解决方案,但你可以在(非SSL/HTTPS)http/web socket端口上运行你的CRO应用程序 - localhost,然后有一个Nginx服务器(配置为提供https/ssl流量)来处理传入的公共https/ssl请求,并将它们作为普通的http流量通过nginx反向代理机制传递到你的应用程序中(这也经常被称为ssl终止),这样你就不需要在CRO端处理https/ssl了。 唯一的障碍可能是WebSockets协议是否能够被Nginx代理很好地处理。我从未尝试过,但根据Nginx文档,你应该没问题-https://www.nginx.com/blog/websocket-nginx/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接