0

I have a websocket server that I need to protect behind a PHP session and currently I'm unable because I can't make PHP to reverse proxy to the websocket server. Let's go to the details.

I have a NGINX server acting as general reverse proxy, that passes the request to the apache server that it's running with the PHP module. This apache-php server is the one that should check if the user has a valid session (no problem with that) and if it does redirect the request to the final websocket server, a x11VNC. If I remove the apache step and proxy pass NGINX directly to x11VNC it works perfectly, but once I want to add the session check, I get stuck.

Searching the internet I have been able to write the following code:

$vnc_request_headers = apache_request_headers();
$vnc_request_headers_simple_array = [];
foreach ($vnc_request_headers as $vnc_request_header => $value) {
array_push($vnc_request_headers_simple_array, $vnc_request_header . ': ' . $value);
}

$options = [
CURLOPT_HTTPHEADER     => $vnc_request_headers_simple_array,
CURLOPT_RETURNTRANSFER => true,     // return web page
CURLOPT_HEADER         => true,     // return headers
CURLOPT_FOLLOWLOCATION => true,     // follow redirects
CURLOPT_ENCODING       => "",       // handle all encodings
CURLOPT_AUTOREFERER    => true,     // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
CURLOPT_TIMEOUT        => 120,      // timeout on response
CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
];

$ch = curl_init('http://192.168.100.13:5900');
curl_setopt_array($ch, $options);

$vnc_response_headers = [];
// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
function($curl, $header) use (&$vnc_response_headers)
{
    $len = strlen($header);
    $header = explode(':', $header, 2);
    if (count($header) < 2) // ignore invalid headers
      return $len;

    $vnc_response_headers[strtolower(trim($header[0]))][] = trim($header[1]);

    return $len;
    }
);

$vnc_response = curl_exec($ch);
$vnc_header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$vnc_httpCode = curl_getinfo($ch , CURLINFO_HTTP_CODE);
curl_close($ch);

$vnc_body = substr($vnc_response, $vnc_header_size);

http_response_code($vnc_httpCode);

foreach ($vnc_response_headers as $vnc_response_header => $array) {
foreach($array as $vnc_response_header_value) {
    header($vnc_response_header . ": " . $vnc_response_header_value);
    }
}

echo $vnc_body;

This grabs the apache icomming headers and forward them to the proxied server, and then graps the proxied answer along with the response headers and code. Then sets the headers and the code and finally echoes the body. I have tested it and works perfectly with standard http(s) requests. The request headers reach the proxied server and the response headers reach the client browser.

But it doesn't work when working with websocket connections, curl gets stuck in curl_exec(). Maybe because websocket connections are never really closed until the data streamming it's closed from one party? I'm pretty lost because it's my first time working with websockets.

How to reverse proxy the websocket request, and all the following messages exchange that is going to take place between x11VNC and the client, with PHP?

1
  • My first thought with webserver and websocket is node.js. There is a library that I have zero experience with github.com/websockets/ws ... I would prefer PHP (I like PHP), but PHP is best at thin clients [request info - supply info - close], and its garbage collector is ideal for this usage. I don't know if how much that may have changed ... php.net/manual/en/features.gc.performance-considerations.php ... but PHP in the space it was designed for is very good. node.js is designed for server applications. Oct 31, 2022 at 17:58

1 Answer 1

4

That's exactly the issue. Websockets are a persistent and bi-directional connection, unlike your typical http requests. This means they don't really work with your typical HTTP tools, you need something that can specifically deal with websockets.

As far as I know you can't really use PHP to deal with a websocket via apache, nor do I expect it to be a good idea even if you could. What you'd typically do is essentially write your own websocket server in PHP that is run as it's own service, separate from apache or nginx. You could then code your server to act as a proxy between the vnc server and the browser with whatever extra checks you want.

As an alternative to making your own proxy server (or finding one) you might be able to simply configure Nginx to authenticate the request for you by making a sub-request to your PHP script. I don't use Nginx so not sure if that would work but it sounds promising.

1
  • As an alternative to making your own proxy server (or finding one) you might be able to simply configure Nginx to authenticate the request for you by making a sub-request to your PHP script. I don't use Nginx so not sure if that would work but it sounds promising.
    – Worsha
    Oct 31, 2022 at 14:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.