Thread: Re: SCRAM pass-through authentication for postgres_fdw
On Wed, Dec 4, 2024 at 10:45 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > This is achieved by storing the SCRAM ClientKey and ServerKey obtained > during client authentication with the backend. These keys are then > used to complete the SCRAM exchange between the backend and the fdw > server, eliminating the need to derive them from a stored plain-text > password. What are the assumptions that have to be made for pass-through SCRAM to succeed? Is it just "the two servers have identical verifiers for the user," or are there others? It looks like the patch is using the following property [1]: If an attacker obtains the authentication information from the authentication repository and either eavesdrops on one authentication exchange or impersonates a server, the attacker gains the ability to impersonate that user to all servers providing SCRAM access using the same hash function, password, iteration count, and salt. For this reason, it is important to use randomly generated salt values. It makes me a little uneasy to give users a reason to copy identical salts/verifiers around... But for e.g. a loopback connection, it seems like there'd be no additional risk. Is that the target use case? I haven't looked at the code very closely yet, but the following hunk jumped out at me: > - pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type); > + pg_hmac_ctx *ctx = pg_hmac_create(PG_SHA256); Why was that change made? Thanks, --Jacob [1] https://datatracker.ietf.org/doc/html/rfc5802#section-9
On Wed, 4 Dec 2024 at 23:11, Jacob Champion <jacob.champion@enterprisedb.com> wrote: > It makes me a little uneasy to give users a reason to copy identical > salts/verifiers around... But for e.g. a loopback connection, it seems > like there'd be no additional risk. Is that the target use case? I don't think that necessarily has to be the usecase, clustering/sharding setups could benefit from this too. PgBouncer supports the same functionality[1]. I only see advantages over the alternative, which is copying the plaintext password around. In case of compromise of the server, only the salt+verifier has to be rotated, not the actual user password. Regarding the actual patch: This definitely needs a bunch of documentation explaining how to use this and when not to use this.
On Wed, Dec 4, 2024 at 3:05 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote: > I only see advantages over the > alternative, which is copying the plaintext password around. In case > of compromise of the server, only the salt+verifier has to be rotated, > not the actual user password. Sure, I'm not saying it's worse than plaintext. But a third alternative might be actual pass-through SCRAM [1], where either you expect the two servers to share a certificate fingerprint, or explicitly disable channel bindings on the second authentication pass in order to allow the MITM. (Or, throwing spaghetti, maybe even have the primary server communicate the backend cert so you can verify it and use it in the binding?) All that is a metric ton more work and analysis, though. --Jacob [1] https://www.postgresql.org/message-id/9129a012-0415-947e-a68e-59d423071525%40timescale.com
On Wed, Dec 4, 2024 at 3:39 PM Jacob Champion <jacob.champion@enterprisedb.com> wrote: > actual pass-through SCRAM (This was probably not a helpful way to describe what I'm talking about; the method here in the thread could be considered "actual pass-through SCRAM" as well. Proxied SCRAM, maybe?) --Jacob
Em qua., 4 de dez. de 2024 às 20:39, Jacob Champion <jacob.champion@enterprisedb.com> escreveu: > > On Wed, Dec 4, 2024 at 3:05 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote: > > I only see advantages over the > > alternative, which is copying the plaintext password around. In case > > of compromise of the server, only the salt+verifier has to be rotated, > > not the actual user password. > > Sure, I'm not saying it's worse than plaintext. But a third > alternative might be actual pass-through SCRAM [1], where either you > expect the two servers to share a certificate fingerprint, or > explicitly disable channel bindings on the second authentication pass > in order to allow the MITM. (Or, throwing spaghetti, maybe even have > the primary server communicate the backend cert so you can verify it > and use it in the binding?) I'm not understanding how these options would work for this scenario. I understand your concern about making the users copying the SCRAM verifiers around but I don't understand how this third alternative fix this issue. Would it be something similar to what you've implemented on [1]? The approach on this patch is that when the backend open the connection with the foreign server, it will use the ClientKey stored from the first client connection with the backend to build the final client message that will be sent to the foreign server, which was created/validated based on verifiers of the first backend. I can't see how the foreign server can validate the client proof without having the identical verifiers with the first backend. I tested a scenario where the client open a connection with the backend using channel binding and the backend open a connection with the foreign server also using channel binding and everything seems to works fine. I don't know if I missing something here, but here is how I've tested this: - Configure build system to use openssl meson setup build -Dssl=openssl ... - Start two Postgresql servers - Configure to use ssl on both servers ssl = on ssl_cert_file = '/path/to/server.crt' ssl_key_file = '/path/to/server.key' - Changed pg_hba to use ssl on both servers hostssl all all 127.0.0.1/32 scram-sha-256 hostssl all all ::1/128 scram-sha-256 - Performed all foreign server setup (CREATE SERVER ...) - Connect into the backend using channel_binding=require psql "host=127.0.0.1 dbname=local sslmode=require channel_binding=require" - Execute a query on fdw server I've also put a debug message before strcmp(channel_binding, b64_message) [2] to ensure that channel binding is being used on both servers and I got the log message on both servers logs. Sorry if I misunderstood your message, I probably missed something here. [1] https://www.postgresql.org/message-id/9129a012-0415-947e-a68e-59d423071525%40timescale.com [2] src/backend/libpq/auth-scram.c#read_client_final_message -- Matheus Alcantara EDB: https://www.enterprisedb.com
On Wed, Dec 11, 2024 at 11:04 AM Matheus Alcantara <matheusssilv97@gmail.com> wrote: > Em qua., 4 de dez. de 2024 às 20:39, Jacob Champion > <jacob.champion@enterprisedb.com> escreveu: > > Sure, I'm not saying it's worse than plaintext. But a third > > alternative might be actual pass-through SCRAM [1], where either you > > expect the two servers to share a certificate fingerprint, or > > explicitly disable channel bindings on the second authentication pass > > in order to allow the MITM. (Or, throwing spaghetti, maybe even have > > the primary server communicate the backend cert so you can verify it > > and use it in the binding?) > > I'm not understanding how these options would work for this scenario. > I understand your concern about making the users copying the SCRAM > verifiers around but I don't understand how this third alternative fix > this issue. Would it be something similar to what you've implemented on > [1]? Yeah, I was speaking in reference to my LDAP/SCRAM patchset from a while back. (I'm just going to call that approach "proxied SCRAM" for now.) > The approach on this patch is that when the backend open the > connection with the foreign server, it will use the ClientKey stored > from the first client connection with the backend to build the final > client message that will be sent to the foreign server, which was > created/validated based on verifiers of the first backend. I can't see > how the foreign server can validate the client proof without having > the identical verifiers with the first backend. Correct. The only way this strategy will work is if the verifiers are the same. (Proxied SCRAM allows for different verifiers -- with different salts and/or iterations -- with the same password.) I do like that the action "copy the verifier" is a pretty clear signal that you want the servers to be able to MITM each other. It's less attack surface than having the two servers share a certificate, for sure, and less work than communicating a new binding. Only users that have opted into that are "vulnerable". > I tested a scenario where the client open a connection with the > backend using channel binding and the backend open a connection with > the foreign server also using channel binding and everything seems to > works fine. I don't know if I missing something here, but here is how > I've tested this: All that looks good. Sorry, I hadn't intended to derail your particular proposal with that -- the channel binding problem only shows up with my proxied SCRAM, because the client has to decide which tls-server-end-point to trust and put into the binding. (It's important that your patchset works with channel bindings too, of course, but I don't expect that to be a problem. It shouldn't matter to this approach.) --Jacob