From 082d3b2cb9127f8acfd4d081e69c427a37bae91d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 27 Feb 2016 00:59:17 -0800 Subject: wiki2 authentication bug fix and improvement against timing attack - Bytes type does not have encode method. The expected_hash retrieved from the database is a bytes object. - Use hmac.compare_digest instead of == to avoid timing attacks as a recommended security best practice. See https://www.python.org/dev/peps/pep-0466/ https://bugs.python.org/issue21306 and https://codahale.com/a-lesson-in-timing-attacks/ for details. Note, however, this was not backported to py2.6. For a tutorial, I am OK with stating this will not work on Python 2.6 with a clear warning note at the start of the tutorial and on the authentication step. --- docs/tutorials/wiki2/src/authentication/tutorial/models/user.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2') diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py index 6fb32a1b2..6499491b2 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py @@ -1,4 +1,5 @@ import bcrypt +import hmac from sqlalchemy import ( Column, Integer, @@ -23,7 +24,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) - return expected_hash == actual_hash + return hmac.compare_digest(expected_hash, actual_hash) return False -- cgit v1.2.3 From ee4050ac0a4a60343eb736a90b47113ebfbb60a3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Feb 2016 01:22:20 -0800 Subject: wiki2 revert unnecessary hmac stuff --- docs/tutorials/wiki2/src/authentication/tutorial/models/user.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'docs/tutorials/wiki2') diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py index 6499491b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/authentication/tutorial/models/user.py @@ -1,5 +1,4 @@ import bcrypt -import hmac from sqlalchemy import ( Column, Integer, @@ -26,5 +25,5 @@ class User(Base): if self.password_hash is not None: expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) - return hmac.compare_digest(expected_hash, actual_hash) + return expected_hash == actual_hash return False -- cgit v1.2.3 From a26a08b92f390aeaa3eb0c39241bb5e76f5a72ea Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 28 Feb 2016 01:29:55 -0800 Subject: apply change to all src/*/user.py --- docs/tutorials/wiki2/src/authorization/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/models/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/tests/tutorial/models/user.py | 2 +- docs/tutorials/wiki2/src/views/tutorial/models/user.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/tutorials/wiki2') diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py b/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py index 6fb32a1b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/authorization/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/models/tutorial/models/user.py b/docs/tutorials/wiki2/src/models/tutorial/models/user.py index 6fb32a1b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/models/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/models/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py index 6fb32a1b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/tests/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/tests/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False diff --git a/docs/tutorials/wiki2/src/views/tutorial/models/user.py b/docs/tutorials/wiki2/src/views/tutorial/models/user.py index 6fb32a1b2..6bd3315d6 100644 --- a/docs/tutorials/wiki2/src/views/tutorial/models/user.py +++ b/docs/tutorials/wiki2/src/views/tutorial/models/user.py @@ -23,7 +23,7 @@ class User(Base): def check_password(self, pw): if self.password_hash is not None: - expected_hash = self.password_hash.encode('utf8') + expected_hash = self.password_hash actual_hash = bcrypt.hashpw(pw.encode('utf8'), expected_hash) return expected_hash == actual_hash return False -- cgit v1.2.3