Re: Prevent query cancel packets from being replayed by an attacker (From TODO) - Mailing list pgsql-hackers
From | Sebastian Cabot |
---|---|
Subject | Re: Prevent query cancel packets from being replayed by an attacker (From TODO) |
Date | |
Msg-id | CAEmynK8m7GYwdob_R0Uc_KAT2L_9xeutM9FM74p7S3w0UHzZKw@mail.gmail.com Whole thread Raw |
In response to | Re: Prevent query cancel packets from being replayed by an attacker (From TODO) (Laurenz Albe <laurenz.albe@cybertec.at>) |
List | pgsql-hackers |
On Wed, Mar 31, 2021 at 5:44 PM Laurenz Albe <laurenz.albe@cybertec.at> wrote: > > On Wed, 2021-03-31 at 16:54 +0300, Sebastian Cabot wrote: > > My name is Sebastian and I am new to this list and community. > > I have been following PostgreSQL for several years and I love the work done on > > it, but I never had the chance (time) to join. > > > > I was going through the TODO list and studied the code and the thread discussing the > > optional fixes and I think I have a solution to this one which has the following advantages: > > 1. No change to the protocol is needed > > 2. Can be implemented in a both forward and backward compatible way > > 3. Does not require any shared memory trickery > > 4. Is immune to brute force attacks (probably) > > > > If this is still something we wish to fix I will be happy to share the details (and > > implement it) - I don't wish to burden you with the details if there is no real interest in solving this. > > Thank you for your willingness to help! > > Sure, this is the place to discuss your idea, go ahead. > > Right now is the end of the final commitfest for v14, so people > are busy getting patches committed and you may get less echo than normally. > > Yours, > Laurenz Albe > Thank you Laurenz. I will post the details. Hopefully some developers will find the time to review the idea. Summary of the problem: To cancel a query a query cancel message is sent. This message is always sent unencrypted even if SSL is enabled because there is a need for the cancel message to be sent from signals. This opens up the possibility of a replay attack since the cancel message contains a cancel auth key which does not change after the backend is started. Summary of the solution proposed in the discussion on the thread: https://www.postgresql.org/message-id/489C969D.8020800@enterprisedb.com Not all the details were agreed upon but the trend was as follows: 1. The current way of canceling a request shall continue to be supported (at least until the next protocol version update) 2. A new cancel message format and processing method shall be supported alongside the original and the server shall advertise in the startup runtime parameters whether this new method is supported 3. A new libpq client that supports the new method shall know to use it if the server supports it 4. The new method involves the client sending a hashed representation of the cancel authkey so that the key is never sent in clear text 5. There will be a mechanism (an integer which is incremented before every cancel message) to generate a new hash for every request 6. When using the new method the postmaster shall check that the integer of a new request is larger than the one used for the last request 8. There will be a postmaster configuration parameter to decide whether the new method is enforced or is optional The above suggestion is not bad and quite appealing but in reality it forms a protocol change, It requires changes to both the server and the client. Details for new suggestion: 1. We notice that the incentive for the elaborate solution proposed is that the cancel auth key cannot be regenerated easily (Without touching shared memory in a way that is not trivial with the current implementation especially for non EXEC_BACKEND). 2. If a new cancelation authkey can be regenerated once a cancel message was sent then we could just send the new key and no changes to libpq or the protocol are required. 2.1. One problem with such an approach is that other clients (JDBC?) only read the key at startup and this shall be addressed below 3. There will be a postmaster configuration parameter to decide whether the new method is enforced or is optional Here is how the new design will allow generating a new "random" authkey without any shared memory trickery: We will add two backend variables: int32 original_cancel_key; (To allow cancels from client that do not update the key in case the new method is not enforced by the server) char random_bits[32]; POSTMASTER: When creating a new backend the original_cancel_key shall have a copy of the random key generated. ramdom_bits shall be initialized using pg_strong_random When a new cancel message request arrives: POSTMASTER: (If the new method is not enforced then also a match against the original_cancel_key shall be accepted) If the message's cancelAuthCode matches the current cancel_key then 1. Generate a new key by a deterministic algorithm from random_bits 2. regenerate random_bits using a SHA256 of the current key and the current random bits 3. As in today send SIGINT to backend BACKEND: Upon receiving SIGINT mark that a new key should be generated. When appropriate in the loop: 1. Generate a new key by a deterministic algorithm from random_bits (same way POSTMASTER did so it will get the exact same key) 2. regenerate random_bits using a SHA256 of the current key and the current random bits (The same way POSTMANGER did so it will get the same randomness) 3. Send new key to client So if the server does not enforce the new method old clients will work just the same. For clients using the new libpq or derived implementations the new secure cancel shall be the default whether the server enforces it or not. I welcome any comments or questions. Thanks Sebastian
pgsql-hackers by date: