Skip to content

Commit f1b9862

Browse files
committed
Use secrets module instead of random for security-sensitive token generation
Replace random.sample() with secrets.choice() for generating PKCE code verifiers, OAuth2 state parameters, and OIDC nonces. The random module uses Mersenne Twister which is not cryptographically secure. The secrets module uses os.urandom(), providing a CSPRNG suitable for security tokens. This also fixes a subtle entropy reduction caused by random.sample() drawing without replacement, which prevented character repetition.
1 parent 1f71ede commit f1b9862

File tree

2 files changed

+6
-5
lines changed

2 files changed

+6
-5
lines changed

msal/oauth2cli/oauth2.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import base64
1414
import sys
1515
import functools
16-
import random
16+
import secrets
1717
import string
1818
import hashlib
1919

@@ -277,8 +277,9 @@ def _scope_set(scope):
277277

278278
def _generate_pkce_code_verifier(length=43):
279279
assert 43 <= length <= 128
280+
alphabet = string.ascii_letters + string.digits + "-._~"
280281
verifier = "".join( # https://tools.ietf.org/html/rfc7636#section-4.1
281-
random.sample(string.ascii_letters + string.digits + "-._~", length))
282+
secrets.choice(alphabet) for _ in range(length))
282283
code_challenge = (
283284
# https://tools.ietf.org/html/rfc7636#section-4.2
284285
base64.urlsafe_b64encode(hashlib.sha256(verifier.encode("ascii")).digest())
@@ -488,7 +489,7 @@ def initiate_auth_code_flow(
488489
raise ValueError('response_type="token ..." is not allowed')
489490
pkce = _generate_pkce_code_verifier()
490491
flow = { # These data are required by obtain_token_by_auth_code_flow()
491-
"state": state or "".join(random.sample(string.ascii_letters, 16)),
492+
"state": state or "".join(secrets.choice(string.ascii_letters) for _ in range(16)),
492493
"redirect_uri": redirect_uri,
493494
"scope": scope,
494495
}

msal/oauth2cli/oidc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22
import base64
33
import time
4-
import random
4+
import secrets
55
import string
66
import warnings
77
import hashlib
@@ -238,7 +238,7 @@ def initiate_auth_code_flow(
238238
# Here we just automatically add it. If the caller do not want id_token,
239239
# they should simply go with oauth2.Client.
240240
_scope.append("openid")
241-
nonce = "".join(random.sample(string.ascii_letters, 16))
241+
nonce = "".join(secrets.choice(string.ascii_letters) for _ in range(16))
242242
flow = super(Client, self).initiate_auth_code_flow(
243243
scope=_scope, nonce=_nonce_hash(nonce), **kwargs)
244244
flow["nonce"] = nonce

0 commit comments

Comments
 (0)