mirror of https://github.com/tiangolo/fastapi.git
📝 Update docs for JWT to prevent timing attacks (#14908)
This commit is contained in:
parent
a2e51363c7
commit
d11f820ac3
|
|
@ -116,7 +116,11 @@ And another utility to verify if a received password matches the hash stored.
|
|||
|
||||
And another one to authenticate and return a user.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}
|
||||
|
||||
When `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash.
|
||||
|
||||
This ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames.
|
||||
|
||||
/// note
|
||||
|
||||
|
|
@ -152,7 +156,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response
|
|||
|
||||
Create a utility function to generate a new access token.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}
|
||||
|
||||
## Update the dependencies { #update-the-dependencies }
|
||||
|
||||
|
|
@ -162,7 +166,7 @@ Decode the received token, verify it, and return the current user.
|
|||
|
||||
If the token is invalid, return an HTTP error right away.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}
|
||||
|
||||
## Update the `/token` *path operation* { #update-the-token-path-operation }
|
||||
|
||||
|
|
@ -170,7 +174,7 @@ Create a `timedelta` with the expiration time of the token.
|
|||
|
||||
Create a real JWT access token and return it.
|
||||
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
|
||||
{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}
|
||||
|
||||
### Technical details about the JWT "subject" `sub` { #technical-details-about-the-jwt-subject-sub }
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class UserInDB(User):
|
|||
|
||||
password_hash = PasswordHash.recommended()
|
||||
|
||||
DUMMY_HASH = password_hash.hash("dummypassword")
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
app = FastAPI()
|
||||
|
|
@ -70,6 +72,7 @@ def get_user(db, username: str):
|
|||
def authenticate_user(fake_db, username: str, password: str):
|
||||
user = get_user(fake_db, username)
|
||||
if not user:
|
||||
verify_password(password, DUMMY_HASH)
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class UserInDB(User):
|
|||
|
||||
password_hash = PasswordHash.recommended()
|
||||
|
||||
DUMMY_HASH = password_hash.hash("dummypassword")
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
app = FastAPI()
|
||||
|
|
@ -69,6 +71,7 @@ def get_user(db, username: str):
|
|||
def authenticate_user(fake_db, username: str, password: str):
|
||||
user = get_user(fake_db, username)
|
||||
if not user:
|
||||
verify_password(password, DUMMY_HASH)
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ class UserInDB(User):
|
|||
|
||||
password_hash = PasswordHash.recommended()
|
||||
|
||||
DUMMY_HASH = password_hash.hash("dummypassword")
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="token",
|
||||
scopes={"me": "Read information about the current user.", "items": "Read items."},
|
||||
|
|
@ -85,6 +87,7 @@ def get_user(db, username: str):
|
|||
def authenticate_user(fake_db, username: str, password: str):
|
||||
user = get_user(fake_db, username)
|
||||
if not user:
|
||||
verify_password(password, DUMMY_HASH)
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class UserInDB(User):
|
|||
|
||||
password_hash = PasswordHash.recommended()
|
||||
|
||||
DUMMY_HASH = password_hash.hash("dummypassword")
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="token",
|
||||
scopes={"me": "Read information about the current user.", "items": "Read items."},
|
||||
|
|
@ -84,6 +86,7 @@ def get_user(db, username: str):
|
|||
def authenticate_user(fake_db, username: str, password: str):
|
||||
user = get_user(fake_db, username)
|
||||
if not user:
|
||||
verify_password(password, DUMMY_HASH)
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
return False
|
||||
|
|
|
|||
Loading…
Reference in New Issue