novnc / noVNC

VNC client web application
https://novnc.com
Other
11.56k stars 2.3k forks source link

Vnc encrypt -SecurityTypes=VeNCrypt,TLSVnc #1230

Closed samgoud closed 3 years ago

samgoud commented 5 years ago

Describe the bug We had been using novnc for our project with -ssl-only option Recently we had been asked to encrypt vnc traffic using -SecurityTypes=VeNCrypt,TLSVnc with the vnc server. We are using tigervnc 1.9 server. When we enabled tiger vnc server with above option, novnc started to complaint "unsupported security types (19,19)". Is -SecurityTypes=VeNCrypt,TLSVnc supported? If not is there a workaround suggested? To Reproduce Start vncserver with -SecurityTypes=VeNCrypt,TLSVnc option like: $> tigervnc-1.9.0.x86_64/usr/bin/vncserver -SecurityTypes=VeNCrypt,VncAuth vnc server started on display 1 $> noVNC/utils/launch.sh --vnc localhost:5901 --cert novnc.pem --ssl-only --listen 6103 Open the suggested url in any browser Expected behavior The vncserver desktop should appear on browser.

Screenshots image

Client (please complete the following information): Chrome, Firefox Server (please complete the following information):

CendioOssman commented 5 years ago

I'm afraid we do not support any VNC encryption. Right now the recommended solution is to use https to the WebSocket proxy, and then make sure the connection between the WebSocket proxy and VNC server is secured some other way (e.g. by having them on the same machine).

I don't think this will improve anytime soon as the browsers don't give access to TLS code from JavaScript, and it will probably be very slow in pure JavaScript.

samgoud commented 5 years ago

The webproxy uproach will secure the data channel between client browser and the server, but the vnc server port by itself independently is still vulnerable if the hacker comes to know the server machine name and vnc port number. The IT team run tests on each port independently and flag if the data from that port is not encrypted.

  1. Is there any alternate way we can encrypt the vnc server and use novnc with it
  2. Can you give little more details on your statement "browsers don't give access to TLS code from JavaScript"
  3. If we have to update noVNC code ourselves to enable support for VeNCrypt, how do you suggest technically to go about it?

Sorry for asking too many questions in a single thread. noVNC had been a critical application in our project evolution so far and we want to get through this security concern with a clean solution.

CendioOssman commented 5 years ago

The webproxy uproach will secure the data channel between client browser and the server, but the vnc server port by itself independently is still vulnerable if the hacker comes to know the server machine name and vnc port number. The IT team run tests on each port independently and flag if the data from that port is not encrypted.

Unencrypted doesn't mean it's easier for a random attacker to get in. Encryption is there to protect against eavesdropping. So if the network is otherwise secure against eavesdropping, then encryption doesn't really add any extra security.

But you can always configure a firewall to only allow connections to the VNC server from the WebSocket proxy.

  1. Is there any alternate way we can encrypt the vnc server and use novnc with it

Not that I know of. noVNC doesn't support any type of VNC encryption. A more advanced WebSocket proxy might be able to do something, but I'm not aware of any such proxy.

  1. Can you give little more details on your statement "browsers don't give access to TLS code from JavaScript"

The browser obviously has a TLS client engine since it can use https. But that engine is not available from JavaScript. So we cannot write code in noVNC that uses that TLS engine to talk to the VNC server.

  1. If we have to update noVNC code ourselves to enable support for VeNCrypt, how do you suggest technically to go about it?

The only feasible way is to get a TLS library written in JavaScript and hook that up to noVNC. I'd be cautious about this approach though as writing a secure TLS library is hard. Adding a TLS library with security issues might cause more problems than running unencrypted.

CendioOssman commented 5 years ago

For reference, how we solve this in ThinLinc is to have the proxy and the VNC server on the same machine. At that point there is no network and no need for protection against eavesdropping.

I'm not sure how OpenStack does it. @DirectXMan12, any insight?

DirectXMan12 commented 5 years ago

IIRC (it's been a few years since I worked on OpenStack at this point), the plan (which I had partially implemented) was a kind-of mitm proxy that set up the security by doing the initial handshake with security to the server, then faking a no-security handshake based on that with the client. After that, it would strip the security and proceed from there.

samgoud commented 5 years ago

Thanks for the inputs. We are evaluating few options along with the suggestions from you.

One option we thought of is to block the access to VNC port from external world, so that VNC is accessed only through websockify running on the same machine. To acheive this we used -localhost option of xVNC while starting vncserver. This option disables access to VNC from remote machines and allows access from that machine only.

Do you see any security loopholes in this approach. Please suggest.

samgoud commented 5 years ago

One quick question on your input "But you can always configure a firewall to only allow connections to the VNC server from the WebSocket proxy." Please provide few details on the recommended way to do this.

CendioOssman commented 5 years ago

Do you see any security loopholes in this approach.

That should protect you from eavesdropping, yes.

Please provide few details on the recommended way to do this.

Assuming you know the IP address of the WebSocket proxy, simply configure your firewall to reject any other IP address trying to connect to the VNC port. This would force an attacker to spoof the IP address, which may be difficult or impossible depending on the network layout.

Exactly how you do this depends on your firewall, so you'll have to check its documentation.

nmz787 commented 3 years ago

What is the supported option for -SecurityTypes= for use with noVNC?

nmz787 commented 3 years ago

-SecurityTypes=None seemed to move things along... though websockify chokes with (https://github.com/novnc/websockify/issues/493) and the proxy I built never seems to hear back from the VNC after getting the machine name:

thread2 started
listening for VNC data...
thread1 started
VNC socket_get_til_timeout DONE with: b'RFB 005.000\n'
got data from vnc, sending it back
got websocket data 12 - bytearray(b'RFB 003.008\n')
sent websocket data to vnc
listening for VNC data...
VNC socket_get_til_timeout DONE with: b'\x02\x01\xc0'
got data from vnc, sending it back
got websocket data 1 - bytearray(b'\x01')
sent websocket data to vnc
listening for VNC data...
VNC socket_get_til_timeout DONE with: b'\x00\x00\x00\x00'
got data from vnc, sending it back
got websocket data 1 - bytearray(b'\x01')
sent websocket data to vnc
listening for VNC data...
VNC socket_get_til_timeout DONE with: b'\x05\x00\x04\x00 \x18\x00\x01\x00\xff\x00\xff\x00\xff\x10\x08\x00\x00\x00\x00\x00\x00\x00\x1eXvnc: nmz787 on theVNCmachine:5'
got data from vnc, sending it back
got websocket data 20 - bytearray(b'\x00\x00\x00\x00 \x18\x00\x01\x00\xff\x00\xff\x00\xff\x00\x08\x10\x00\x00\x00')
sent websocket data to vnc
listening for VNC data...

here's the proxy code (I'm using Flask and the flask-sockets way of hooking up a websocket to my webserver):


@vnc_bp.route('/websocket/<path:url_path>')
def web_socket(ws, url_path):
    print(f'\t * websocket from ({url_path})')
    if url_path not in vnc_seen:
        vnc_seen[url_path] = test_vnc_server
        vnc_server_port = vnc_seen[url_path]
        vnc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        vnc.settimeout(5)
        server, port = vnc_server_port
        vnc.connect((server, port))
        websocket_to_vnc_server_map[vnc_server_port] = vnc
        t2 = threading.Thread(target=thread2_to_ws, args=(ws, vnc))
        t2.start()
    vnc_server_port = vnc_seen[url_path]
    vnc = websocket_to_vnc_server_map[vnc_server_port]
    thread1_to_vnc(ws, vnc)
    print('\t * websocket thread started')
    print('\t * websocket thread startup done, returning')

def thread1_to_vnc(ws, vnc):
    print('thread1 started')
    while True: #not ws.closed:
        with lock:
            data = ws.receive()
            print(f'got websocket data {len(data) if data else data} - {data}')
            if data:
                vnc.send(data)
                print('sent websocket data to vnc')
        time.sleep(0.01)
    print('thread1 done')

def thread2_to_ws(ws, vnc):
    vnc.setblocking(1)
    print('thread2 started')
    while vnc:
        with lock:
            print('listening for VNC data...')
            client_data = socket_get_til_timeout(vnc)
            if client_data:
                print('got data from vnc, sending it back')
                ws.send(client_data)
        time.sleep(0.01)
    print('thread2 done')

def socket_get_til_timeout(sock):
    data = bytes()
    while sock:
        data = sock.recv(1024)
        if data!=b'':
            print(f'VNC socket_get_til_timeout DONE with: {data}')
            break
    return data
CendioOssman commented 3 years ago

I'm afraid debugging your WebSocket proxy is about outside of our scope. You also seem to be using RealVNC, which is something I would recommend against during testing as it is closed and more difficult for the open community to help you with.

Still, the initial issue with VeNCrypt is as resolved as it will ever be, so I'll go ahead and close this issue.