Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Authentication Required for wallets that need high cost requests #790

Open
gits7r opened this issue Apr 10, 2019 · 1 comment
Open

Comments

@gits7r
Copy link

gits7r commented Apr 10, 2019

I have drafted a proposal. This is for the long term, but posting it here so we can properly think about it.

Motivation

In Q2 of 2019 all Bitcoin Mainnet (Coin: BitcoinSegwit) public ElectrumX servers listed on the default list were severely DOSed, but not like a traditional DOS that just fills the internet pipe and consumes bandwidth, but at the application level by sending expensive requests (in terms of CPU usage and disk I/O usage) and disconnecting before hitting the bandwidth limits, then reconnecting again. This made servers quite unavaialble for genuine, honest clients.

Obviously, this cannot continue and "cost" (CPU and disk I/O) limits have to be used by default in addition to the session bandwidth limits.

While this fixes the problem for small and medium size wallets (regular users), it does not fix it for large wallets or merchants that use electrum to accept payments and have high transaction volume. Such special users might want to "pay" or otherwise subscribe in order to access ElectrumX servers with higher cost limits than the default.

This is why we need a simple way to add support for restricted / authenticated access for ElectrumX. For simple use cases like one server per such "special" user, this is not required as a private ElectrumX server can simply be configured and sent to the user. We aim to provide a solution for the use cases where a single ElectrumX servers tends to accept multiple "special" users and be able to identity a potential abuser inflitrated. Or maybe one server operator just wants to accept freely, more users that have the same remote IP address and just wants to be able to identify the abusers.

Authenticated sessions

We add a new variable:
AUTH_REQUIRED = no | yes | privileged
[default = no]

yes = clients can connect only if proper authentication (cookie) was provided.
no = anyone can connect
privileged = anyone can connect, but also privileged users that provide cookie authentication get higher resource limits.

privileged mandatory requires more cost variables with PRIVILEGED_ prefix, that indicate the higher resource limits for authenticated users.

Also a new variable for credentials data is required:
AUTHORIZED_USERS = /path/to/file

Where we will find a file in the format:
<public_key> <max_sessions> NL

where:
username = username, email or other identification method for server operator to know which user that is;
public_key = secp256k1 public key of the user
max_sessions = n (server operator can configure, based on subscription, how many sessions that user is allowed. They can be either from one IP either from different IP addresses).

Cookie Authentication

Why cookie and no simple username and password scheme?
We can use username + password scheme as well, but this will require us to also require a PKI layer to ensure username and password are provided via a secure channel (SSL) and are not vulnerable to man-in-the-middle attacks. Currently we use self signed certificates for SSL sessions, and save them to disk in order to identify a potential future man-in-the-middle attempt. But, this does not help users that are connecting to a server for the first time, and are MITM right from their first connection.

Cookie authentication will be simple:
The server operator adds a secp256k1 public key for an user.
The user digitally signs (ECDSA) an authentication message and sends it to the server that looks as follows:
HELLO|<64 bytes of random data>|
<digital_signature>

This message should be signed with the private key corresponding to the public key added by the server operator for the user.

timestamp is used to protect against replay attacks. Server should not accept an auth cookie if its timestamp is older than 30 mins or more than 29 mins in the future from server's time. The 64 bytes of random data exist to ensure the server can take a sha512 of the cookie and remember to not accept it again for N hours.

This still allows a MITM attacker to steal the cookie entirely and connect to the server, but I think it's slightly better than plain username and password because at least it cannot be used in multiple places on demand. Maybe we can think of something better here.

If all these match, the sessions are authenticated and labeled properly so they can be tied to the username in question.

Disconnect Authenticated Abusers

Sometimes, either abusers subscribe (if they want to pull of a costly attack), either they steal credential data from honest users, in order to continue to DOS the resources of the servers. The goal is for such users to be identified and removed from the authorized users list, so the others remain unaffected. It's the user's job to properly secure the credential data, or otherwise to subscribe again or ask for a new credential in case they lost it or it was stolen.

This means, when an authenticated user triggers the cost per session limit, its username / public key (credential) is removed from the authorized list, and logged in a separate file, instead of the IP address like we have for non authenticated users. The cost of the CPU usage and disk I/O is endured by the username and public key, instead of the IP address. This helps a lot servers that are accessible via .onion domains and see all their clients as being 127.0.0.1

Also, if the PRIVILEGED_ cost variables for authenticated users are not hit, but the user requests something that consumes them all, then disconnects and connects again it achieves a similar DOS. ElectrumX needs to be able to identify such abnormal activity and tag it to an username / public key and remove such users from the authorized list, then log them to a separate file: removed_users

removed_users will contain:
<public_key> <max_sessions> <timestamp_of_removal> <some_other_info> NL

Electrum Wallet Client Server Auth Plugin

For a good user experience, it makes sense to add a simple GUI utility to Electrum wallet that is displayed when "Server Requires Authentication" is checked, that only asks for the private secp256k1 key so it can sign the cookie.

The private key can of course be one of the keys in the wallet, but haven't thought of this for the different wallet types we provide. The utility will allow users to either generate a new random secp256k1 key for server authentication, either provide an existing one (maybe generated by the server's registration form).

This is just a draft, more comments are needed. Apologies in advance if something is obviously wrong, I just thought of this. Looking forward for feedback.
This work is placed in the public domain.

@kyuupichan
Copy link
Owner

Yes I've long wanted to do something similar to what you describe, but more formally in the protocol. It's obivous (to me at least) that indexing services will be paid for in the future; that alone makes some of the things you mention moot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants