At the Udacity.com there is a course called Web Development. The lecturer has told us about cookies, how to sign cookies, what salt is and that we must always keep hashes of passwords in the database. Then he gave us a homework and then he published a solution. And only here we have seen the whole picture: how it all should work together.
Below is Python and Google App Engine. But, please, don't be afraid. The code seems to be readable like pseudo code.
import hashlib
import hmac
secret = 'iamsosecret'
def make_secure_val(val):
return '%s|%s' % (val, hmac.new(secret, val).hexdigest())
def check_secure_val(secure_val):
val = secure_val.split('|')[0]
if secure_val == make_secure_val(val):
return val
def make_salt(length = 5):
return ''.join(random.choice(letters) for x in xrange(length))
def make_pw_hash(name, pw, salt = None):
if not salt:
salt = make_salt()
h = hashlib.sha256(name + pw + salt).hexdigest()
return '%s,%s' % (salt, h)
def valid_pw(name, password, h):
salt = h.split(',')[0]
return h == make_pw_hash(name, password, salt)
class User(db.Model):
name = db.StringProperty(required = True)
pw_hash = db.StringProperty(required = True)
email = db.StringProperty()
@classmethod
def register(cls, name, pw, email = None):
pw_hash = make_pw_hash(name, pw)
return User(parent = users_key(),
name = name,
pw_hash = pw_hash,
email = email)
@classmethod
def login(cls, name, pw):
u = cls.by_name(name)
if u and valid_pw(name, pw, u.pw_hash):
return u
class BlogHandler(webapp2.RequestHandler):
def set_secure_cookie(self, name, val):
cookie_val = make_secure_val(val)
self.response.headers.add_header(
'Set-Cookie',
'%s=%s; Path=/' % (name, cookie_val))
def read_secure_cookie(self, name):
cookie_val = self.request.cookies.get(name)
return cookie_val and check_secure_val(cookie_val)
def login(self, user):
self.set_secure_cookie('user_id', str(user.key().id()))
def logout(self):
self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/')
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
uid = self.read_secure_cookie('user_id')
self.user = uid and User.by_id(int(uid))
Let's scrutinize what we have here.
- Function make_secure_val produces something like this: 'keyword|6f21001bbf8bfbd8c04b9d537df1e314'
- Function make_secure_val is used in the function set_secure_cookie. So, it is used for login.
- Function make_secure_val makes use of a secret key, but doesn't use salt.
- Function make_pw_hash(name, pw, salt = None) produces something like this: 'some_salt,c984cade696390b71ff914293c53767502ea542bfd0e7240a051e7ead2c60077'
- Function make_pw_hash prepares a hashed password that will be kept in the database. User inputs username and the password in the form, then data from the form become arguments of this make_pw_hash function.
- Function make_pw_hash uses salt but doesn't use a secret key.
- Function make_pw_hash for some reasons mixed username into the hash.
Well, I can't understand anything here. I would say this is all not secure.
Questions:
1. Why the teacher did not use salt for cookies?
2. Why he didn't use the secret key for making hashes to put passwords into the database?
3. Why he mixed username for making hashes to put passwords into the database?
4. We can see two approaches for making hashes: one for cookies and another for the database. Why they are separated? Isn't it more practical to unify: always use a secret key and salt. Less code. And good security. But he separated. Why?
By the way The teacher's solution
And by the way: the teacher is Steve Huffman (http://ift.tt/1gGuh0M). If he did that way, maybe he has heavy reasons for that.
Aucun commentaire:
Enregistrer un commentaire