Last active
March 9, 2021 23:35
-
-
Save nikhilkumarsingh/6d4b5ae222df2e5a4ae8c45192bb5c67 to your computer and use it in GitHub Desktop.
Introduction to secrets in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"attachments": {}, | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# secrets module in Python\n", | |
"\n", | |
"\n", | |
"\n", | |
"\n", | |
"> The secrets module is used for generating **cryptographically strong random numbers** suitable for managing data such as passwords, account authentication, security tokens, and related secrets.\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Why not use `random` module?\n", | |
"\n", | |
"> A random number generator (RNG) is a device that generates a sequence of numbers or symbols that cannot be reasonably predicted better than by a random chance. Random number generators can be true hardware random-number generators (HRNG), which generate genuinely random numbers, or pseudo-random number generators (PRNG), which generate numbers that look random, but are actually deterministic, and can be reproduced if the state of the PRNG is known.\n", | |
"\n", | |
"- `random` module uses a **pseudo**-random number generator, [Mersenne Twister](https://en.wikipedia.org/wiki/Mersenne_Twister).\n", | |
"\n", | |
"- The PRNG-generated sequence is not truly random, because it is completely determined by an initial value, called the PRNG's **seed**.\n", | |
"\n", | |
"- Hence, the entire seemingly random sequence can be reproduced if the **seed** value is known.\n", | |
"\n", | |
"- Fast and reproducible\n", | |
"\n", | |
"- Good for simulation & modelling applications and games.\n", | |
"\n", | |
"- Not secure for cryptographic applications because next output is predictable from earlier outputs." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import random" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"random.seed(3)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"[4, 10, 9, 3, 6, 10, 8, 10, 2, 10]\n" | |
] | |
} | |
], | |
"source": [ | |
"print([random.randint(1,10) for _ in range(10)])" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Python support for *hardware random-number generators* (HRNG)\n", | |
"\n", | |
"### How does HRNG work?\n", | |
"\n", | |
"- measures some physical phenomenon that is expected to be random\n", | |
"\n", | |
"- measures from sources of natural entropy, such as \n", | |
" - atmospheric noise, \n", | |
" - thermal noise, and\n", | |
" - other external electromagnetic and quantum phenomena.\n", | |
" \n", | |
"- they are rate-limited until enough entropy is harvested to meet the demand/ Until then, they are blocked.\n", | |
"\n", | |
"- Due to this blocking behavior, HRNGs can be slow.\n", | |
"\n", | |
"\n", | |
"----\n", | |
"In order to fetch truly random data from OS using Python: [os.urandom](https://docs.python.org/3/library/os.html#os.urandom)\n", | |
"\n", | |
"> If seed value is not provided explicitly, `random` module first tries to read `os.urandom` value for setting seed. If read fails, current time + process identifier is set as the seed. [Source](https://github.com/python/cpython/blob/master/Modules/_randommodule.c#L265-#L283)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import os" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"b'\\xdeRk\\x7f'" | |
] | |
}, | |
"execution_count": 5, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"os.urandom(4)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"`random` module also provides a random number generator built over `os.urandom`, called [`SystemRandom`](https://github.com/python/cpython/blob/3.8/Lib/random.py#L709-#L736)." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"srandom = random.SystemRandom()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"[7, 3, 1, 7, 7, 2, 3, 8, 9, 2]\n" | |
] | |
} | |
], | |
"source": [ | |
"print([srandom.randint(1,10) for _ in range(10)])" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## [`secrets`](https://docs.python.org/3/library/secrets.html) methods\n", | |
"\n", | |
"### 1. `secrets.choice`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import secrets" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"3" | |
] | |
}, | |
"execution_count": 9, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.choice([1,3,5,7])" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 2. `secrets.randbelow`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"4" | |
] | |
}, | |
"execution_count": 10, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.randbelow(5)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 3. `secrets.randbits`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"783" | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.randbits(10)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"> The secrets module provides functions for generating secure tokens, suitable for applications such as password resets, hard-to-guess URLs, and similar.\n", | |
"\n", | |
"### 4. `secrets.token_bytes`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"b'\\xc2W\\x07\\x8c-'" | |
] | |
}, | |
"execution_count": 12, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.token_bytes(5)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 5. `secrets.token_hex`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'9fdd38ef6ea434dc778bafe1a48187f46abb194fd18352efb224efec8ef55e07'" | |
] | |
}, | |
"execution_count": 13, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.token_hex()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 6. `secrets.token_urlsafe`\n", | |
"\n", | |
"[Source](https://github.com/python/cpython/blob/master/Lib/secrets.py#L61)\n", | |
"\n", | |
"[Base64 table](https://en.wikipedia.org/wiki/Base64#Base64_table)\n", | |
"\n", | |
"[base64.urlsafe_b64encode](https://github.com/python/cpython/blob/3.8/Lib/base64.py#L111-#L118)\n", | |
"\n", | |
"[How many bytes should tokens use?](https://docs.python.org/3/library/secrets.html#how-many-bytes-should-tokens-use)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'k1ANyx4ljvKWuQ'" | |
] | |
}, | |
"execution_count": 14, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"secrets.token_urlsafe(10)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 7. `secrets.compare_digest`\n", | |
"\n", | |
"To reduce the risk of timing attacks.\n", | |
"\n", | |
"> A timing attack is a security exploit that allows an attacker to discover vulnerabilities in the security of a computer or network system by studying how long it takes the system to respond to different inputs.\n", | |
"\n", | |
"[Example](https://ropesec.com/articles/timing-attacks/)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"52.2 ns ± 4.71 ns per loop (mean ± std. dev. of 200 runs, 10 loops each)\n" | |
] | |
} | |
], | |
"source": [ | |
"%%timeit -n 10 -r 200\n", | |
"\"abc\" == \"abc\"" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"141 ns ± 11.9 ns per loop (mean ± std. dev. of 200 runs, 10 loops each)\n" | |
] | |
} | |
], | |
"source": [ | |
"%%timeit -n 10 -r 200\n", | |
"secrets.compare_digest(\"abc\", \"abc\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"[Recipes and best practices](https://docs.python.org/3/library/secrets.html#recipes-and-best-practices)" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "pyenv37", | |
"language": "python", | |
"name": "pyenv37" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.7.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment