(ws) Implement simple header based websocket authorization technique to reject
This commit is contained in:
		@@ -2,6 +2,12 @@
 | 
			
		||||
 | 
			
		||||
All changes to this project will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## [11.0.5] - 2020-12-17
 | 
			
		||||
 | 
			
		||||
(ws) Implement simple header based websocket authorization technique to reject
 | 
			
		||||
client which do not supply a certain header ("Authorization") with a special
 | 
			
		||||
value (see doc).
 | 
			
		||||
 | 
			
		||||
## [11.0.4] - 2020-11-16
 | 
			
		||||
 | 
			
		||||
(ixwebsocket) Handle EINTR return code in ix::poll and IXSelectInterrupt
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								docs/ws.md
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								docs/ws.md
									
									
									
									
									
								
							@@ -195,6 +195,63 @@ Server: Python/3.7 websockets/8.0.2
 | 
			
		||||
Upgrade: websocket
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It is possible to pass custom HTTP header when doing the connection handshake,
 | 
			
		||||
the remote server might process them to implement a simple authorization
 | 
			
		||||
scheme.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
src$ ws connect -H Authorization:supersecret ws://localhost:8008
 | 
			
		||||
Type Ctrl-D to exit prompt...
 | 
			
		||||
[2020-12-17 22:35:08.732] [info] Authorization: supersecret
 | 
			
		||||
Connecting to url: ws://localhost:8008
 | 
			
		||||
> [2020-12-17 22:35:08.736] [info] ws_connect: connected
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Uri: /
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Headers:
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Connection: Upgrade
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Sec-WebSocket-Accept: 2yaTFcdwn8KL6IzSMj2u6Le7KTg=
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Server: ixwebsocket/11.0.4 macos ssl/SecureTransport zlib 1.2.11
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Upgrade: websocket
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Received 25 bytes
 | 
			
		||||
ws_connect: received message: Authorization suceeded!
 | 
			
		||||
[2020-12-17 22:35:08.736] [info] Received pong ixwebsocket::heartbeat::30s::0
 | 
			
		||||
hello
 | 
			
		||||
> [2020-12-17 22:35:25.157] [info] Received 7 bytes
 | 
			
		||||
ws_connect: received message: hello
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the wrong header is passed in, the server would close the connection with a custom close code (>4000, and <4999).
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[2020-12-17 22:39:37.044] [info] Upgrade: websocket
 | 
			
		||||
ws_connect: connection closed: code 4001 reason Permission denied
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## echo server
 | 
			
		||||
 | 
			
		||||
The ws echo server will respond what the client just sent him. If we use the
 | 
			
		||||
simple --http_authorization_header we can enforce that client need to pass a
 | 
			
		||||
special value in the Authorization header to connect.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ ws echo_server --http_authorization_header supersecret
 | 
			
		||||
[2020-12-17 22:35:06.192] [info] Listening on 127.0.0.1:8008
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] New connection
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] remote ip: 127.0.0.1
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] id: 0
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Uri: /
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Headers:
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Authorization: supersecret
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Connection: Upgrade
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Host: localhost:8008
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Sec-WebSocket-Key: eFF2Gf25dC7eC15Ab1135G==
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Sec-WebSocket-Version: 13
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] Upgrade: websocket
 | 
			
		||||
[2020-12-17 22:35:08.735] [info] User-Agent: ixwebsocket/11.0.4 macos ssl/SecureTransport zlib 1.2.11
 | 
			
		||||
[2020-12-17 22:35:25.157] [info] Received 7 bytes
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Websocket proxy
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,9 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IXConnectionState.h"
 | 
			
		||||
#include "IXNetSystem.h"
 | 
			
		||||
#include "IXSelectInterrupt.h"
 | 
			
		||||
#include "IXSocketTLSOptions.h"
 | 
			
		||||
#include "IXNetSystem.h"
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.0.4"
 | 
			
		||||
#define IX_WEBSOCKET_VERSION "11.0.5"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -1367,7 +1367,8 @@ namespace ix
 | 
			
		||||
                            const ix::SocketTLSOptions& tlsOptions,
 | 
			
		||||
                            bool ipv6,
 | 
			
		||||
                            bool disablePerMessageDeflate,
 | 
			
		||||
                            bool disablePong)
 | 
			
		||||
                            bool disablePong,
 | 
			
		||||
                            const std::string& httpHeaderAuthorization)
 | 
			
		||||
    {
 | 
			
		||||
        spdlog::info("Listening on {}:{}", hostname, port);
 | 
			
		||||
 | 
			
		||||
@@ -1393,9 +1394,9 @@ namespace ix
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        server.setOnClientMessageCallback(
 | 
			
		||||
            [greetings](std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                        WebSocket& webSocket,
 | 
			
		||||
                        const WebSocketMessagePtr& msg) {
 | 
			
		||||
            [greetings, httpHeaderAuthorization](std::shared_ptr<ConnectionState> connectionState,
 | 
			
		||||
                                                 WebSocket& webSocket,
 | 
			
		||||
                                                 const WebSocketMessagePtr& msg) {
 | 
			
		||||
                auto remoteIp = connectionState->getRemoteIp();
 | 
			
		||||
                if (msg->type == ix::WebSocketMessageType::Open)
 | 
			
		||||
                {
 | 
			
		||||
@@ -1409,6 +1410,19 @@ namespace ix
 | 
			
		||||
                        spdlog::info("{}: {}", it.first, it.second);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!httpHeaderAuthorization.empty())
 | 
			
		||||
                    {
 | 
			
		||||
                        auto authorization = msg->openInfo.headers["Authorization"];
 | 
			
		||||
                        if (authorization != httpHeaderAuthorization)
 | 
			
		||||
                        {
 | 
			
		||||
                            webSocket.close(4001, "Permission denied");
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            webSocket.sendText("Authorization suceeded!");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (greetings)
 | 
			
		||||
                    {
 | 
			
		||||
                        webSocket.sendText("Welcome !");
 | 
			
		||||
@@ -3039,6 +3053,7 @@ int main(int argc, char** argv)
 | 
			
		||||
    std::string publisherRolesecret;
 | 
			
		||||
    std::string sendMsg("hello world");
 | 
			
		||||
    std::string filename;
 | 
			
		||||
    std::string httpHeaderAuthorization;
 | 
			
		||||
    ix::SocketTLSOptions tlsOptions;
 | 
			
		||||
    ix::CobraConfig cobraConfig;
 | 
			
		||||
    ix::CobraBotConfig cobraBotConfig;
 | 
			
		||||
@@ -3185,6 +3200,7 @@ int main(int argc, char** argv)
 | 
			
		||||
    echoServerApp->fallthrough();
 | 
			
		||||
    echoServerApp->add_option("--port", port, "Port");
 | 
			
		||||
    echoServerApp->add_option("--host", hostname, "Hostname");
 | 
			
		||||
    echoServerApp->add_option("--http_authorization_header", httpHeaderAuthorization, "Hostname");
 | 
			
		||||
    echoServerApp->add_flag("-q", quiet, "Quiet / only display warnings and errors");
 | 
			
		||||
    echoServerApp->add_flag("-g", greetings, "Greet");
 | 
			
		||||
    echoServerApp->add_flag("-6", ipv6, "IpV6");
 | 
			
		||||
@@ -3507,8 +3523,14 @@ int main(int argc, char** argv)
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("echo_server"))
 | 
			
		||||
    {
 | 
			
		||||
        ret = ix::ws_echo_server_main(
 | 
			
		||||
            port, greetings, hostname, tlsOptions, ipv6, disablePerMessageDeflate, disablePong);
 | 
			
		||||
        ret = ix::ws_echo_server_main(port,
 | 
			
		||||
                                      greetings,
 | 
			
		||||
                                      hostname,
 | 
			
		||||
                                      tlsOptions,
 | 
			
		||||
                                      ipv6,
 | 
			
		||||
                                      disablePerMessageDeflate,
 | 
			
		||||
                                      disablePong,
 | 
			
		||||
                                      httpHeaderAuthorization);
 | 
			
		||||
    }
 | 
			
		||||
    else if (app.got_subcommand("push_server"))
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user