-
Notifications
You must be signed in to change notification settings - Fork 0
Security
James Brucker edited this page Jun 16, 2025
·
5 revisions
Passwords should be stored as salted hashes. Good hashing algorithms, from strongest to weakest, are:
-
Argon2 (especially Argon2id) — Strongest
- Winner of the Password Hashing Competition; memory-hard, highly configurable, and resistant to GPU/ASIC attacks.
-
scrypt
- Also memory-hard and resistant to hardware attacks, but less flexible and slightly older than Argon2.
-
bcrypt
- Very well-tested and widely used, but less resistant to modern hardware attacks than Argon2 and scrypt.
-
PBKDF2 — Weakest
- Not memory-hard; more vulnerable to brute-force attacks with specialized hardware, but still secure with high iteration counts. But why choose it? A "high iteration count" today may not be good enough in a few years.
Applicability to an application using FastAPI + Postgres on backend, Vue.js on frontend.
- First choice should be Argon2, specifically, Argon2id.
- Supported by libraries such as
argon2-cffiin Python. - In FastAPI use the
argon2-cffilibrary for hashing and verifying passwords. - Store the hash (and salt, if not embedded) in the PostgreSQL database, as
BYTEAfor raw binary orTEXTfor encoded strings.
- Second choice should be scrypt.
- Provided by Python's
hashlibmodule. - Example:
import os.urandom() import hashlib my_salt = os.urandom(16) # 16 binary bytes hash = hashlib.scrypt( password=b'my_password', # "bytes" object, at most 1024 bytes salt=my_salt, # "bytes" object, recommended 16+ random bytes n=16384, # cpu/memory cost factor r=8, # blocksize p=1 # parallelization factor ) # hash is "bytes" object. To get hex form: hex_encoded = hash.hex() # to get in base64 form, which is more compact (88 bytes vs 128 bytes): import base64 b64_encoded = base64.standard_b64encode(hash) # use base64.standard_b64decode() to get back the original hash "bytes"
- Provided by Python's
The values of n, r, and p are not necessarily secure.
| Param | Typical value | Meaning |
|---|---|---|
n |
16384 | Iteration count, affects time and memory |
r |
8 | Block size, affects memory and cpu use |
p |
1 | Parallization. Number of core to use. |
The memory required to compute the scrypt hash is:
Memory required = 128 * n * r * p Bytes
# Example
= 128 * 16384 * 8 * 1 = 16 MBOn a laptop computer with 8GB of memory running Ubuntu 20.04, setting n=16384, r=16, p=1 resulted in an out of memory error from Python.