-
Notifications
You must be signed in to change notification settings - Fork 456
Fix Insecure Default Configuration #1554
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
base: development
Are you sure you want to change the base?
Fix Insecure Default Configuration #1554
Conversation
Accidentally pushed with OED_PRODUCTION set to yes
huss
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to @Zachary-Squires & @Zach-O-Bates for this contribution. I've made some comments to consider. I'm happy to discuss them. I did some testing but not complete as I'm going to wait for any changes to do that.
| if [ -f ".env" ]; then | ||
| if grep -q "^OED_TOKEN_SECRET=" .env; then | ||
| sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env | ||
| else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment applies in a general way but put here. I'm thinking about the fact that there are settings in .env and docker-compose.yml that apply to the same case. I think originally it was designed to allow flexibility in how the values were given and to override them. I think the reality is that people don't use this ability. Also, security has become more important so I'm thinking having it in two places is less desirable since people might miss one. Finally, I think OED will be adopting new ways to set values that is more secure and easier so getting to one way now might help for that future effort. First: What do you think about getting rid of one of the ways to set these values? Second: If yes, then should we only use the docker-compose.yml file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have thoughts on setting it this way? Do you think it should be left for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided it could be a separate effort and just opened issue #1569 about doing this.
src/scripts/installOED.sh
Outdated
| echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env | ||
| fi | ||
| fi | ||
| #If the user is in production and their postgres password has been left default, generating a random one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is actually changing the password for Postgres. I'm not an expert but from what I understand, the POSTGRES_PASSWORD environment variable is used when the DB is initialized. This happens at an earlier stage so the original value is used. I'm also unsure if it changes it if done on a later startup. I tried checking with login and it was not clear but seems it might be an issue. We should discuss this.
I don't know how the token is impacted or if that is okay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I did some testing and it seems like you're exactly right, for the first time since the database is created before this is run it uses the default password but after that it uses the new one. I'm not sure if there's anything I can do about that but I'm open to ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this had been addressed but my testing did not find it working. I did the following:
- Without OED running, I removed the postgres-data/ directory. This forces complete initialization of the DB on the next startup of OED.
- I edited src/scripts/installOED.sh so it had:
if [ "$dostart" == "yes" ]; then
if [ "$INSTALL_MODE" = "development" ]; then
so it used my development environment to force the password initialization to a script generated one.
- Started OED and it said it set the password.
- Shut down OED.
- Edited postgres_data/pg_hba.conf to change trust to password in all local connections to force PG to ask for a password.
- Restart OED.
- Open a shell on the OED Docker database container.
- Do
psql -U oed. It asks for the password. If I give an invalid one it fails. If I use the one output by the first run of the install script then it fails. If I use the default OED PG password then it works. This is why I think it is not changing the password.
- Do
Do you have thoughts or ideas? I'm happy to talk with you about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not currently randomizing the password for the oed user, just the postgres superuser. I can also do it for oed if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting we talked about this and you are working to make that happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both passwords are now set but, as you told me, you have to restart OED for it to work. I know you are working on this.
Added: 1. Banners for the make sure to change this value notifications, also added a notification for the token secret. 2. Fixed spelling error. 3. Added spaces to comments. 4. A variable that checks what the installation type is at the start and is used for all checks.
Added comments in docker-compose.yml to alert users as to the fact passwords are only drawn from this file once. Added something to the .env file to show the code that the password has already been generated. Changed a redundant if statement to an else.
huss
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zachary-Squires Thank you for the updated version. A number of comments are now resolved. I added a new comment on a couple of old ones and added a few new ones. Please let me know if you need anything.
| if [ -f ".env" ]; then | ||
| if grep -q "^OED_TOKEN_SECRET=" .env; then | ||
| sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env | ||
| else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have thoughts on setting it this way? Do you think it should be left for now?
src/scripts/installOED.sh
Outdated
| echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env | ||
| fi | ||
| fi | ||
| #If the user is in production and their postgres password has been left default, generating a random one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this had been addressed but my testing did not find it working. I did the following:
- Without OED running, I removed the postgres-data/ directory. This forces complete initialization of the DB on the next startup of OED.
- I edited src/scripts/installOED.sh so it had:
if [ "$dostart" == "yes" ]; then
if [ "$INSTALL_MODE" = "development" ]; then
so it used my development environment to force the password initialization to a script generated one.
- Started OED and it said it set the password.
- Shut down OED.
- Edited postgres_data/pg_hba.conf to change trust to password in all local connections to force PG to ask for a password.
- Restart OED.
- Open a shell on the OED Docker database container.
- Do
psql -U oed. It asks for the password. If I give an invalid one it fails. If I use the one output by the first run of the install script then it fails. If I use the default OED PG password then it works. This is why I think it is not changing the password.
- Do
Do you have thoughts or ideas? I'm happy to talk with you about this.
Changes to address feedback on 1/19, added/edited comments, changed changePass.js to changePostgresPass.js
huss
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zachary-Squires I'm trying to get all PRs up-to-date so I looked at this one even though you are still working on it. I resolved some comments and left one to think about along with any other open ones.
src/scripts/changePostgresPass.js
Outdated
| console.error('Error during Postgres password change:', error.message); | ||
|
|
||
| if (error.message.includes('ECONNREFUSED')) { | ||
| console.error('Database is not accepting connections yet.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarifying what the timeout was for. In src/scripts/installOED.sh, it also checks for ECONNREFUSED and then does the wait if it happens. It also makes sure it only tries a max number of times (10) and then errors out. I think that might be better than always calling the setTimeout. Thus, I propose a loop in changePassword and wait if there is a connection error with a max number of loops before it reports and error. The wait could then be reduced to 3 seconds as in installOED.sh so it runs faster in most cases. What do you think about that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the status of this?
src/scripts/installOED.sh
Outdated
| echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env | ||
| fi | ||
| fi | ||
| #If the user is in production and their postgres password has been left default, generating a random one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting we talked about this and you are working to make that happen.
huss
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to @Zachary-Squires for addressing many previous comments. I've made a few more to consider and commented on a few older ones. I think this is getting close.
| // Update .env with PostgreSQL and OED user passwords | ||
| function updateEnvFile(postgresPassword, oedPassword) { | ||
| let env = ''; | ||
| if (fs.existsSync(ENV_PATH)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding some comments about what the logic is doing in this function would be helpful.
|
|
||
| // Generate a secure random password | ||
| function generatePassword() { | ||
| return crypto.randomBytes(18).toString('base64'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tab indenting has become space indenting. Could it please be changed back. Let me know if you need any help.
| if (error.message.includes('ECONNREFUSED')) { | ||
| console.error('Database is not accepting connections yet.'); | ||
| } else if (error.message.includes('password authentication')) { | ||
| console.error('Authentication failed — default password may already be changed.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that it is written to .env, does this still happen regularly or is it a rare event?
I saw that if I tried to change the password twice via manually doing the npm command then it failed this way. I know you told me you were still trying to get it to work after the initial startup and I wonder if this relates to that. What I mean is maybe the process.env.POSTGRES_PASSWORD is not updated on change but I'm very uncertain about this. Whatever it is, it would be nice to track down both the initial setting and future changes. I note it seemed to work fine on the first change of the password via the npm command.
| - PGDATA=/var/lib/postgresql/data/pgdata | ||
| - POSTGRES_PASSWORD=pleaseChange # default postgres password that should be changed for security. | ||
| # The postgres database will only pull from this value on the first | ||
| # startup of OED. If a change is desired after this, one must manually |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does one still have to use SQL or will the npm command now do it?
| if [ -f ".env" ]; then | ||
| if grep -q "^OED_TOKEN_SECRET=" .env; then | ||
| sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env | ||
| else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided it could be a separate effort and just opened issue #1569 about doing this.
src/scripts/changePostgresPass.js
Outdated
| console.error('Error during Postgres password change:', error.message); | ||
|
|
||
| if (error.message.includes('ECONNREFUSED')) { | ||
| console.error('Database is not accepting connections yet.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the status of this?
| @@ -0,0 +1,96 @@ | |||
| /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wondering about the location of this file. All the other files in this directory are scripts of .sh, .bash, etc. Given this, would it make sense and could this be move the src/server/util/?
| "webData": "node -e 'require(\"./src/server/data/websiteData.js\").insertWebsiteData()'", | ||
| "addLogMsg": "node -e 'require(\"./src/server/services/addLogMsg.js\").addLogMsgToDB()'" | ||
| "addLogMsg": "node -e 'require(\"./src/server/services/addLogMsg.js\").addLogMsgToDB()'", | ||
| "changePostgresPassword": "node ./src/scripts/changePostgresPass.js" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this directly call changePasswords() as some npm commands do above?
|
|
||
| async function changePasswords() { | ||
| const postgresPassword = process.argv[2] || generatePassword(); | ||
| const oedPassword = process.argv[2] || generatePassword(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal but should both passwords have to be the same? Maybe use [2] and [3] so can be different?
src/scripts/installOED.sh
Outdated
| echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env | ||
| fi | ||
| fi | ||
| #If the user is in production and their postgres password has been left default, generating a random one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both passwords are now set but, as you told me, you have to restart OED for it to work. I know you are working on this.
Description
Changes installOED.sh and docker-compose.yml to automatically generate POSTGRES_PASSWORD and OED_TOKEN_SECRET when OED is launched in production mode. This should remediate an issue where OED_TOKEN_SECRET could be forged to allow a login as an admin. Will also make the postgres database more secure as the password will be much more robust by default. Additionally, installOED.sh now specifically checks if OED_PRODUCTION is no rather than just checking if it is not yes.
Developed and implemented by:
Zachary Squires - https://github.com/Zachary-Squires
Zachary Bates - https://github.com/Zach-O-Bates
Type of change
Checklist
Limitations
In order to fully remediate the insecure default configuration we will need to use a separate docker file when launching in development and production, this will be done in a separate PR since it will be intrusive to every OED developer.