With the scram-sha-256 protocol, does Postgres server encrypt the client's password when initializing the connection so that authentication is secure and the password cannot be read?
It is even better than encrypted, it is salted and hashed. Not only can an eavesdropper not readily reverse it back to the raw password, the server can't either. A weakness though is that if you connect to a malicious server, it can simply insist on not using scram, and the default client will silently comply.
Related
I was able to get SCRAM-SHA-256 authentication to work with pgpool, but I haven't been able to find a good example how to set this up in pgbouncer. I'm trying to use auth_query. In postgres, the user that pgbouncer will connect as has the password encrypted and stored in SCRAM-SHA-256. But I don't know how to create the entries in userlist.txt. This is supposed to be the format:
SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
What exactly are the storedkey and serverkey and how do I generate those? Which tools can I use to create this? In pgpool, I can use pg_enc but I don't see anything for pgbouncer.
You don't construct the SCRAM hashed password yourself, you get it by querying the pg_authid table in the PostgreSQL database:
SELECT rolpassword
FROM pg_authid
WHERE rolname = 'pgbouncer';
However, as the documentation says:
The passwords or secrets stored in the authentication file serve two purposes. First, they are used to verify the passwords of incoming client connections, if a password-based authentication method is configured. Second, they are used as the passwords for outgoing connections to the backend server, if the backend server requires password-based authentication (unless the password is specified directly in the database's connection string). The latter works if the password is stored in plain text or MD5-hashed. SCRAM secrets can only be used for logging into a server if the client authentication also uses SCRAM, the PgBouncer database definition does not specify a user name, and the SCRAM secrets are identical in PgBouncer and the PostgreSQL server (same salt and iterations, not merely the same password). This is due to an inherent security property of SCRAM: The stored SCRAM secret cannot by itself be used for deriving login credentials.
So if that user is used as auth_user, you cannot use a SCRAM hashed password for that user, but you have to use the clear text password.
I'm trying to connect to my database using Knex like so:
const client = knex({
client: 'postgresql',
connection: {
host: '127.0.0.1',
user: 'me',
database: 'my_db'
}
});
client('some_table').then(console.log);
When I created the database (using createdb my_db at the command line) I set no password. At the command line I can run psql -d my_db and it works just fine.
However, when I try to use Knex, I get an error:
Unhandled rejection error: password authentication failed for user "me"
This happens whether I set a null password, an empty string ('') password, or leave the field off of the configuration entirely.
Can anyone explain why Knex insists on failing password authentication ... when there is no password (and when I can connect without one at the command line just fine)?
PostgreSQL does not permit login based on the presence/absence of a password. Rather, all login authentication is handled via pg_hba.conf. In your particular case--creating the me user without a password (or using null or '', as you would describe it)--the absence of the password doesn't necessarily allow your user to log in. In fact, setting no password will not allow that user to log in unless pg_hba.conf was set to some password-less setting (i.e., peer or trust).
If you want password-less login for the me user (I assume for testing/development purposes, as having password-less login is not good security practice in production), you could simply set trust-level authentication in pg_hba.conf:
#conn_origin database user ip_mask auth_method
host all me 0.0.0.0/0 trust
The more secure method of implementing password-less authentication would be to use a .pgpass file or set the PGPASSWORD environment variable. Seeing that you are trying to use knex.js, you may be better off with tweaking pg_hba.conf as above. Again, I don't know what your intentions are, but please be safe out there ;)
Disclosure: I work for EnterpriseDB (EDB)
When executing this postgres command:
EXECUTE 'CREATE USER myuser WITH UNENCRYPTED PASSWORD ''my+password''';
I see the error:
RoundhousE encountered an error.
Npgsql.PostgresException (0x80004005): 0A000: UNENCRYPTED PASSWORD is no longer supported
Is there a workaround for this, or will the password need to be manually encrypted and supplied without the UNENCRYPTED keyword?
No. All you have to do is to omit the UNENCRYPTED.
You can supply both encrypted and unencrypted passwords that way, and PostgreSQL can tell the difference automatically.
PostgreSQL 10+ no longer support user creation with UNENCRYPTED password,
create it with ENCRYPTED:
CREATE USER myuser WITH ENCRYPTED PASSWORD ''my+password''
I am connecting to a local PostgreSQL database with an md5 hashed password.
It works but I want to understand what is happening under the hood.
Does pq hash the password before it is sent over the network? How would it know whether to hash it or leave it as plain text? The server (in pg_hba.conf) is the one who specifies the authentication method of how the password is sent over the connection.
Is there a handshake that goes on between pq and psql before the connection string with the password is sent over?
user := "foo_user"
password := "test"
dbname := "bar"
connectionString := fmt.Sprintf(
"user=%s password=%s dbname=%s",
user,
password,
dbname)
db, err := sql.Open("postgres", connectionString)
The user was created with a password via:
ALTER USER foo_user WITH PASSWORD 'test';
And verified that the password is being stored as a hash:
postgres=# SELECT rolname, rolpassword from pg_authid;
rolname | rolpassword
-------------------+-------------------------------------
postgres |
pg_signal_backend |
foo_user | md51083525553eab8f4090ada980d2b86e7
(3 rows)
And pg_hba.conf is completely unmodified:
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
There are two places where password hashing takes place, and they should not be confused.
When a password is set for a role, it is concatenated with the user name and then hashed. This is the password stored in pg_authid, and that is the actual password used by PostgreSQL. PostgreSQL does not use the password you entered, but a hashed version of it, to keep attackers form stealing your password and then trying it outside of PostgreSQL (in case the same password is used in several places).
So to break into a database, you do not actually need to know the clear text password, the “actual” hashed password is enough.
There are two places where the hashing can take place:
On the server side, if you use
CREATE/ALTER ROLE ... PASSWORD 'mypassword';
This is not so good, because the password is sent over the wire in clear text and it can show up in the database log.
On the client side, if you use
CREATE/ALTER ROLE ... PASSWORD 'hashedpassword';
This is better, and it is what psql uses internally if you use the \password command.
During session authentication, if the authentication method specified for the database and user demands it. The server will then respond to the connection request with a AuthenticationMD5Password message (see the documentation).
The client then hashes the clear text password to obtain the actual password, then hashes it again with a random “salt” provided by the server.
The server hashes the password from pg_authid in the same fashion and compares the result.
Is there a way to change the PostgreSQL password encryption method from MD5 to SHA?
If Yes, can you please tell me how?
I am using PostgreSQL 9.5
Pg 10
With PostgreSQL 10, you can set password_encryption to scram-sha-256. From the docs
When a password is specified in CREATE ROLE or ALTER ROLE without writing either ENCRYPTED or UNENCRYPTED, this parameter determines whether the password is to be encrypted. The default value is md5, which stores the password as an MD5 hash. Setting this to plain stores it in plaintext. on and off are also accepted, as aliases for md5 and plain, respectively. Setting this parameter to scram-sha-256 will encrypt the password with SCRAM-SHA-256.
See this post for information about iterations using scram-sha-256
Pg 9.x
This can not be done without actually modifying the source.