Making Docker PostgreSql secure - untrusting local connection, username & password max length - postgresql

Context
So currently I am creating a setup/launcher script that sets up a secure docker container with PostgreSql database on the client's machine.
To make it really secure, my plan is for the script to:
Autogenerate a random username and password
Execute docker run (with -d postgres of course) and with the randomly generated username and password
Autogenerate another set of random username and password
Create a new user with the newly generated username and password
Grant the newly created user with appropriate permissions
Return the credentials (username & password) of the newly created user and not store (in other word forget) the superuser credentials (username & password)
Questions
What are the limitations of Postgresql's username and password? From this source, it seems that the username max length is 64 bytes (so 64 characters) and from this source it seems the max password length is 100 bytes (so 100 characters). Is the information accurate (the sources are pretty old, and I might have misunderstood it)? Also, are only allowed characters alphanumerical? Does it support Base64, MD5, or SHA?
I noticed that I can access the Postgres bash without providing the superuser's password. Upon further research, it seems it's due to the fact that upon creation of the Postgres database, local access is trusted as its automatically configured in pg_hba.conf. What is the command to untrust all connections, including the local one, and any superuser action needs to have a superuser password supplied?
Any suggestion to increase the security, even more, that does not involve self-hosting the database instead of having the client hosting it on his/her machine? (I am aware that this is a broad/off-topic question, therefore feel free to ignore this question)

username and password length:
user names are limited to 63 bytes, like all other identifiers (unless you want to rebuild PostgreSQL).
src/include/pg_config_manual.h has:
/*
* Maximum length for identifiers (e.g. table names, column names,
* function names). Names actually are limited to one less byte than this,
* because the length must include a trailing zero byte.
*
* Changing this requires an initdb.
*/
#define NAMEDATALEN 64
The maximum length of the password depends on the password encryption method and the authentication used. For scram-sha-256, the limit is 1024.
See src/common/saslprep.c:
/*
* Limit on how large password's we will try to process. A password
* larger than this will be treated the same as out-of-memory.
*/
#define MAX_PASSWORD_LENGTH 1024
The limit of 100 that you are quoting is from the psql password prompt, but nobody forces you to use that.
default authentication method
Use the -A option during initdb to specify a different authentication method.
making a docker container safe
Yes, that is too broad. Essentially, if you have the files that make up the database, you can get at all the data, so I would think that impossible.

Related

PostgreSQL user password change from MD5 to scram-sha-265

I was looking at this Change PostgreSQL password encryption from MD5 to SHA question to figure out how to change the hashing of user passwords in Postgres to something other than MD5 since from what I understand it's basically obsolete now.
But I'm curious if a change is going to be required in the pg_hpa.conf file for the server, as according to this tutorial https://blog.bigbinary.com/2016/01/23/configure-postgresql-to-allow-remote-connection.html you need to add the following to it:
host all all 0.0.0.0/0 md5
host all all ::/0 md5
Will the "md5" need to be changed? Or is it purely there to specify a password is required, and won't be affected when changing hashing function to scram-sha-256?
You can retain md5 as an authentication method in pg_hba.conf even if you change password_encryption to scram-sha-256. It is just unusual to do so.
The main reason it is unusual is that with password_encryption = scram-sha-256, the client must understand the new hashing method anyway to be able to calculate the hashed password from the password entered by the user. Then why not use it for a more secure authentication as well?
To avoid confusion, I'd like to add that there are two different password hashing operations going on in PostgreSQL:
The password the user enters is hashed (together with the user name) to produce the actual PostgreSQL password, as stored in pg_authid. This is to avoid the problem that someone steals the password and reuses it on other systems.
During authentication, the server challenges the client to produce a hash of the password (which is already hashed from the previous step) with a certain salt. This “doubly hashed” password is then sent over the line.
Your question, in other words, was: Can we use scram-sha-256 for the first point and md5 for the second?

Dovecot with PostgreSQL users database: Password hashing

I'm trying to set up a Mail Server using Postfix and Dovecot.
I have my users stored in a PostgreSQL database with bcrypt hashed passwords.
After some researching, I found ways to read users from a PostgreSQL database, but with passwords stored in plain text.
How do I set up Dovecot to read users from a PostgreSQL database with bcrypt hashed passwords?
Dovecot fully supports the BLF-CRYPT password scheme since the recent 2.3 release apparently.
It shouldn't make a difference for PostgreSQL what kind of scheme is used, the password is just a text field in the database and it's stored and retrieved in its hashed textual form. The scheme used to hash is known by the first few characters of the password, for instance $2a$ for bcrypt.
Hashing the password can be can be done with doveadm -s BLF-CRYPT and the output copied into the password field of the database in the row corresponding to the user.
For the authentication, dovecot, like postfix, expects a user-supplied SQL query with some documented placeholders in its configuration (see password_query), so it doesn't need to assume any particular structure of a table or view of users.

Default PostgreSQL password encryption method

I want to know what is the default encryption method used (if any) by PostgreSQL if I do not specify ENCRYPTED while Creating a user or Altering a Role.
I read the following on the PostgreSQL website:
Password Storage Encryption
By default, database user passwords are stored as MD5 hashes, so the administrator cannot determine the actual password assigned to the user. If MD5 encryption is used for client authentication, the unencrypted password is never even temporarily present on the server because the client MD5-encrypts it before being sent across the network.
But I am not sure if MD5 encryption method is used only when I use ENCRYPTED while creating/altering role/user.
I am using PostgreSQL 9.5
Thanks
From the docs
These key words control whether the password is stored encrypted in the system catalogs. (If neither is specified, the default behavior is determined by the configuration parameter password_encryption.) If the presented password string is already in MD5-encrypted format, then it is stored encrypted as-is, regardless of whether ENCRYPTED or UNENCRYPTED is specified (since the system cannot decrypt the specified encrypted password string). This allows reloading of encrypted passwords during dump/restore.
password_encryption defaults to true., though you can check it with SHOW password_encryption.
According to the encryption options,
Password Storage Encryption By default, database user passwords are stored as MD5 hashes, so the administrator cannot determine the actual password assigned to the user. If MD5 encryption is used for client authentication, the unencrypted password is never even temporarily present on the server because the client MD5-encrypts it before being sent across the network.

Comparing hashed passwords, Is it better to compare on the server or on the database using SQL?

I am building a system for authentication, and obviously to do so I will need to compare submitted passwords to hashed stored passwords in the database.
As far as I understand, I can either have the web service use SQL to get the hashed password value and salt, and evaluate on the server. Alternatively, I believe I could use SQL to do the comparison using the database, if I first use the server to extract the salt value, hash the salted password and send it to the database to evaluate. In other words:
Method One:
Receive username and password from the user.
Use SQL to extract the user's salt value and hashed password.
Use the salt and the provided password to compute a hashed password.
Evaluate whether to grant access by comparing the stored password with the newly hashed password.
Method Two:
Receive username and password from the user.
Use SQL to extract only the salt value from the database.
Use the salt and provided password to compute a hashed password.
Use an SQL query to compare the stored password with the newly hashed password.
SQL query returns whether the hashed passwords match.
Grant access to user based on results of SQL query.
Which would be the better practice?

How to store passwords exclusively through PostgreSQL

How would I store passwords exclusively in PostgreSQL? I am aware of the pgcrypto library that can be used with PostgreSQL as is outlined here, or below:
INSERT INTO users (name, password) VALUES ('jdoe', crypt('password', gen_salt('md5')));
However, it is still possible that passwords would be stored in plain text within PostgreSQL server logs. Another complicating factor is I do not have direct control over the log configuration.
Is there any way to completely hide the values in a server column, even from the logs?