sethserver / Python

How to Generate a Strong Random Password in Python

Python helps make a lot of things really easy. The conciseness of the language paird with its easy-to-use REPL make it ideal to hack out quick and easy scripts. One thing you can do is quickly and securely generate a strong random password with practically one line of code.

import secrets import string ''.join([secrets.choice(string.ascii_letters + string.digits + string.punctuation) for i in range(16)])

We're using a few python tricks here, I'll start with the innermost statement:

string.ascii_letters + string.digits + string.punctuation

The string module has some useful built-in constants that can be joined together using the plus operator. For this example I'll use the ascii_letters, digits and punctuation strings to create a string of 94 characters that we can choose from to generate our password.

We then use the choice function paired with a list comprehension to pick a specified number of characters from our given string of 94 characters. In the above example I picked 16, feel free to generate a longer password if you'd like. It's important to keep in mind that the choice function does not modify the given population, so there is a chance that it will return the same character multiple times. When gernating strong passwords, you definitely want this to keep entropy high. If you were to remove characters from the set of available choices you would reduce the set of possible outcomes, therefore making the generated password easier to predict or guess.

We finally take the join function to combine the list of random characters that were returned from our list comprehension into a usable string. If you run this a few times you will see a secure unique password generated each time:

>>> import secrets >>> import string >>> ''.join([secrets.choice(string.ascii_letters + string.digits + string.punctuation) for i in range(16)]) '}bN8965TX)h)?q_;' >>> ''.join([secrets.choice(string.ascii_letters + string.digits + string.punctuation) for i in range(16)]) "z'!`FYXa@B0^^6JO" >>> ''.join([secrets.choice(string.ascii_letters + string.digits + string.punctuation) for i in range(16)]) '%?Y@FoJ~%,p-;lvL'

This is a very convenient way to generate strong and secure passwords on-the-fly with nothing more than the Python interpretor. If you are programming a system that stores passwords please keep the following things in mind:

  • Do not ever store users' passwords as plain text. Ever. I will find your code if you do this, and I will revert your pull request.
  • Always hash passwords combined with with unique, non-deterministic salt values.
  • Always log invalid login attempts and alert users of suspicious activity.
  • Always lock accounts after multiple incorrect login attempts.
  • Always use TLS with a valid, up-to-date certificate.
  • Remember: the internet is a scary place filled with viruses, bugs, hackers, bots and the darkweb; let's not make it worse by building crappy password management systems.
  • To prevent brute force login attacks on your dedicated, virtual private, or cloud servers install intrusion detection and prevention software. Both Palo Alto Networks and Alert Logic provide quite comprehensive solutions.
  • Sign package updates with a private key using GnuPG and verify the signature of it with the public key published previously.
  • Use your own domain for all user-facing interactions.
  • Require VPN access for administrators.
  • Never generate users' passwords and transmit the generated passwords via email.
  • Restrict access using a firewall to any internal non-public facing servers and services.
  • Finally, if any of this is confusing, ask questions. Go find a more senior developer and ask them how they would do it.

Good luck and happy passwording!

-Sethers