Storing user passwords securely is one of the most critical responsibilities in building any web application. A breach in password security not only compromises sensitive user data but also erodes trust in the platform as a whole. With increasing cyber threats, ensuring that passwords are stored safely is no longer just a good practice but a necessity. In this article, I’ll walk you through the steps I took to protect passwords for Sharepon, underscoring both the techniques and the mindset needed to safeguard user information.
Why Password-Specific Hashing is Essential
One of the main goals in securing user passwords is to ensure attackers can’t retrieve them, even if your database is compromised. So how do we achieve that? First and foremost, never store passwords in plain text. If attackers hack your database, they’ll likely try to use stolen usernames, emails, and passwords to access other accounts, including emails, bank accounts, or online shopping platforms like Amazon. For users who reuse passwords across different services, a compromised password can lead to devastating consequences.
To prevent this, passwords must be properly encrypted before being stored in the database.
Use a Secure Hashing Function—But Not Just Any Hashing Function
It’s essential to use modern cryptographic hashing functions for password encryption, but be cautious because not all modern hashing functions are appropriate for passwords. Only slow, one-way hashing functions should be used. Why? Because they offer two key benefits:
- Slow: A cryptographic hash function intentionally designed to be computationally expensive so that it is difficult for attackers to brute-force passwords.
- One-way: A function that transforms input data into a fixed-length string of characters and makes it nearly impossible to reverse-engineer the original data.
Thus, popular hashing algorithms like MD-5 and SHA-1 are not ideal to encrypt passwords because they are both fast hashing algorithms. For Sharepon, I chose the bcrypt algorithm because it satisfies both the “slow” and “one-way” requirements, and is specifically designed for password hashing.
Protecting Against Rainbow Table Attacks with Salt
Even with one-way hashing, there’s still a potential vulnerability: precomputation attacks, such as rainbow tables. A rainbow table is a massive precomputed set of hash values that attackers can use to quickly reverse common password hashes. To defend against this, you need to add salt, which is a unique, randomly generated string, to each password before hashing.
Salt ensures that even if two users have the same password, their stored password hashes will be different. This renders rainbow table attacks virtually useless, as each password is represented by a unique hash in the database.
Though salt is only used to create a unique hash and can thus be safely stored in plain text in the database, combining it creatively with the password can further strengthen security. You could also combine two hashing algorithms or handle input lengths exceeding bcrypt’s limit for added safety, though this isn’t strictly necessary.
For Sharepon, which is built using Python Flask, I used the flask_bcrypt module to implement bcrypt and the secrets module to generate random salt. Both modules are beginner-friendly, especially with the help of OpenAI’s GPT-4 models.

Enhancing Database Server Security
While proper password hashing protects your data after a breach, it’s equally important to prevent your database from being compromised in the first place.
For Sharepon, I ran my MySQL database on an Ubuntu server, and I purposely isolated the database on its own server, separate from my web application, to reduce security risks. You can follow a similar setup using other databases like PostgreSQL or different operating systems like Debian — the principles remain the same.
After setting up my Ubuntu server, I created a user with sudo privileges and disabled root login. Root login poses a risk since the username is predictable (“root”), making it a prime target. I also disabled password login in favor of SSH key authentication, which is far more secure. A tip from me: store your SSH key files on a portable drive, so you have a backup in case your local machine fails or is stolen.
Next, I configured a firewall for my server to block all outgoing and incoming connections except for SSH and MySQL. This step ensures that your database and server are not vulnerable to outside attacks.

Finally, after installing MySQL and creating the database, I created a user tied to a specific IP address using the following MySQL commands:
CREATE USER ‘a_username’@’server_ip’ IDENTIFIED BY ‘a_password’;
GRANT ALL PRIVILEGES ON db_name.* TO ‘a_username’@’server_ip’;
FLUSH PRIVILEGES;
- a_username: a unique and hard-to-guess username
- server_ip: the IP address of your web app server, ensuring only this server can access the database
- a_password: a complex and hard-to-guess password
- db_name: the name of the database you have created for your web app
This setup ensures that only a specific user, coming from a specific IP address, can access your database, which adds an additional layer of protection.
Final Words
These are the practices I recommend for securely storing sensitive data like user passwords. While this information isn’t often emphasized in traditional education, it’s crucial for anyone building a web application. I hope you found these insights helpful! If you spot any mistakes or have suggestions for improvement, feel free to reach out to me at contact@nexttofirepit.com.