allinurl / goaccess

GoAccess is a real-time web log analyzer and interactive viewer that runs in a terminal in *nix systems or through your browser.
https://goaccess.io
MIT License
18.46k stars 1.11k forks source link

Goaccess WebSockets authentication #1133

Open ivodvb opened 6 years ago

ivodvb commented 6 years ago

Hi all!

I'm using the goaccess --real-time-html report daemon to view realtime reports in my web browser. The file report.html is secured with basic auth and the website itself is secured with a TLS certificate.

Code to get goaccess stats

Example to get the stats:

curl --include \
     --no-buffer \
     --header "Connection: Upgrade" \
     --header "Upgrade: websocket" \
     --header "Host: example.com:443" \
     --header "Origin: https://example.com:443" \
     --header "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
     --header "Sec-WebSocket-Version: 13" \
     https://example.com:7890/

Expected when secured with e.g. an API key

{"success":false,"msg":"API key missing or invalid"}

Actual response

Full response with all the statistics

When one knows the websocket URL, he can load the goaccess stats directly. I'd like to prevent that. Is there anything built that helps me with that?

allinurl commented 6 years ago

Great question! There's nothing built-in right now, however, I do agree that implementing this would be useful. Do you know how other programs manage the auth part for websocket? Should it be based on an API key? Thanks.

ivodvb commented 6 years ago

@allinurl Thanks for the response!

I'll take a look at a better proposal including some examples and maybe even some code (I'm not a C dev)

jdespatis commented 6 years ago

In order to secure the WebSocket server, you can hide it behind a reverse proxy

In my use case, for example, I use jwilder/nginx-proxy Docker image as the reverse proxy with basic authentification and letsencrypt SSL Behind I have GoAccess Docker image with the WebSocket server activated

the html report is accessible with https://example.com and the WebSocket is accessible with https://example.com/ws/

Both are protected by basic authentification thanks to the reverse proxy

allinurl commented 6 years ago

@jdespatis Awesome! Thanks for sharing this :+1:

FinlayDaG33k commented 4 years ago

I'm also in for having this feature.
Due to the setup my project (and future projects) will have, using basic-authentication is not possible :\

anoraxx commented 1 month ago

@jdespatis

In order to secure the WebSocket server, you can hide it behind a reverse proxy

the html report is accessible with https://example.com and the WebSocket is accessible with https://example.com/ws/

Both are protected by basic authentification thanks to the reverse proxy

I suppose for this to work you use something like --ws-url={USER}:{PASSWORD}@example.com when running goaccess?

allinurl commented 1 month ago

@anoraxx You can handle authentication at the reverse proxy level by using basic authentication, i.e.,:

    # Authentication
    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/.htpasswd;

If the user isn’t logged in, nginx will show a 401 unauthorized error and prompt them to enter a username and password in a browser dialog. After they provide their credentials, nginx will check them against the .htpasswd file. If everything matches, the connection will go through, and the WebSocket connection will start as normal.

anoraxx commented 1 month ago

Ah, so if I previously authenticated when opening example.com in the browser, that auth will also work for the subsequent WebSocket requests to example.com/ws, right? Didn't think about that.

allinurl commented 1 month ago

@anoraxx, I haven't tried this myself, but theoretically, if you add auth_basic to your reverse proxy—specifically the block that opens report.html—it should prevent unauthorized access to the WebSocket if users haven’t authenticated.

Another approach would be to implement authentication by passing a token when the browser performs the connection upgrade. This might be a cleaner solution. If you're comfortable with C and JS/WebSockets, I don't think it would be too difficult to set up. Let me know if you have any questions.