Billyzou0741326 / bilibili-live-monitor-ts

bilibili - b站直播监控
https://billyzou0741326.github.io/bilibili-live-monitor-ts/
MIT License
28 stars 4 forks source link

Enhancement: optional user authentication support #19

Closed blu3mania closed 4 years ago

blu3mania commented 4 years ago

This was originally a PR from master branch. As Billy commented, we will leave this one open for now.

Copied from original PR #18 :

Billyzou0741326 commented 5 hours ago I'm quite hesitant to use url-based authentication. What I have in mind is a full fledged per-user key authentication system stored in a database of some kind, the implementation of which is quite involved.

For now let's leave out the whole authentication part, and perhaps come back to it later.

blu3mania commented 31 seconds ago Sure. In that case I will create a new feature branch and make a PR from there so we can leave it open. After that I will close this one and rebase my master branch back to the same as your HEAD commit.

blu3mania commented 4 years ago

@Billyzou0741326 Continuing the discussion from PR #18 as that PR was close.

RE: I'm thinking of having the client send the verification info after the connection is established. Beyond that, I'm not sure how to design the authentication process, unfortunately,

It really depends on what your goal is and how strong you want its security to be. If you just want to generate a token at client side and send to server to verify, there are many ways. Simple ones include:

  1. Digest algorithm, which can hash a shared secret and send to server to perform the same hash function and verify the result. For example, this PR uses SHA-512 which is quite strong. Obviously hash function is not reversible so you won't be able to see the data before hashing. Also, you can't add dynamic content from one side since the other side needs to know it before calculating the digest, i.e. the shared secret is static.

  2. Symmetric-key algorithm, like AES, which can use the shared secret to encrypt and decrypt the same token. Dynamic content like timestamp can be included for added protection (i.e. reduce the chance of replay). Though, shared secret is still static.

  3. Public-key cryptography, like RSA.

3a). Typically client uses server's public key to encrypt the token (e.g. shared secret), and send to server since only server can decrypt. Though, the request can still be replayed. Timestamp can be used to reduce that risk but it requires client and server to be synchronized to NTP server -- not a big deal but if TTL is short it could be challenging. Obtaining certificate is also an issue. Certainly it is a waste of money to purchase from CAs just for this purpose. Self-signed certs can be used but you may need to hook up certificate validation.

3b). Improved way is to instead have client hold its own private key, e.g. from a personal certificate, and use it to sign the token (all critical parts of the token need to be signed so it cannot be tempered with). At server side, it uses the client's public key to verify the signature. Obviously since only particular client can sign the token, the token itself does not need to be encrypted as there is no way to temper it. Though, request can still be replayed, so TTL of the token needs to be short. It also requires advanced management for each client as server needs to associate their public keys individually. Obtaining certificates becomes even more troublesome...

With all these, we still have the issue that transportation layer is not secured, so the packets can be sniffed at gateway or other devices along the path, and requests could be replayed. Securing the channel will again be an issue. Using self-signed certs is more of a challenge since HTTPS/WSS connection is created by Node.js so allowing self-signed root/ignoring non-matching CN could be harder to do.

You could also use IdP as they are likely TLS enabled. Though, most of them are web based, and require resource provider to register with them... And asking all clients to have an ID registered with IdP are all unrealistic.

Another way is using message level encryption. First establish a shared symmetric key between client and server, likely by using certs (again, certs management...), then use the key to encrypt/decrypt the whole message. Not easy to implement...

There are other things to consider as well:

  1. If you allow client to establish the socket before authentication, you have to hold the socket until authN is done. If that never comes, you could leak a socket. You can use some timeout to clear out sockets that fail to perform authN in time, but it still means sockets can exist in a queue for a while, which enables DoS attack. One way to handle that is IP based auto-ban system, but it won't do much in a DDoS attack.

  2. You could ask token to be provided in the initial connection request, but it means including the token in URL since you can't use POST to create WS connection. And, since client is not using browser, GET and POST doesn't make much of a difference anyway (i.e. there is no browser history here, and both are subject to sniffing unless protected at transportation layer).

  3. Any of these solutions would require client code to be updated to match server code, especially when changing algorithm.

Billyzou0741326 commented 4 years ago

With that, I gather that self signed certs are out of question. As for timestamp synchronization, a GET request to the server might be sufficient.

I'm not too worry about ddos, since sophisticated attacks can even take down our university's firewall—definitely too much for me to handle. If holding sockets for a period of time is a concern, then we can certainly fall back to the url-based solution. In fact, let's do just that.

Personally I don't feel like going down the authentication path. As you probably observed, my knowledge on the subject is rather trivial. I will keep the server open for any connection, at least until it gets under attack :(

blu3mania commented 4 years ago

Sure. Personally I don't need it either since I am not running monitor code from a public server anyway. I will just leave the changes in the branch and try to maintain that branch to be up to date, in case someone want to use it to enforce user authentication.

Billyzou0741326 commented 4 years ago

I would say not to spend too much energy on that, for it being a minor feature. Thanks a lot!

Billyzou0741326 commented 4 years ago

I opened a branch with identical name. Is it possible to direct the PR to that branch instead?

blu3mania commented 4 years ago

I opened a branch with identical name. Is it possible to direct the PR to that branch instead?

Done.