Security fixies.

Generate new salt for every password.
Support different salt for passwords.
Support SHA512 for hashing.
This commit is contained in:
onovy 2015-04-21 10:15:14 +02:00
parent e0941ddffd
commit e14a7b3df8
3 changed files with 71 additions and 12 deletions

View File

@ -47,11 +47,9 @@ use = egg:swauth#swauth
# max_token_life = <same as token_life>
# Specifies how the user key is stored. The default is 'plaintext', leaving the
# key unsecured but available for key-signing features if such are ever added.
# An alternative is 'sha1' which stores only a one-way hash of the key leaving
# An alternative is 'sha512' which stores only a one-way hash of the key leaving
# it secure but unavailable for key-signing.
# auth_type = plaintext
# Used if the auth_type is sha1 or another method that can make use of a salt.
# auth_type_salt = swauthsalt
# This allows middleware higher in the WSGI pipeline to override auth
# processing, useful for middleware such as tempurl and formpost. If you know
# you're not going to use such middleware and you want a bit of extra security,

View File

@ -28,13 +28,10 @@ conditions:
- Write a match(key, creds) method that will take two arguments: the user's
key, and the user's retrieved credentials. Return a boolean value that
indicates whether the match is True or False.
Note that, since some of the encodings will be hashes, swauth supports the
notion of salts. Thus, self.salt will be set to either a user-specified salt
value or to a default value.
"""
import hashlib
import os
#: Maximum length any valid token should ever be.
@ -80,6 +77,20 @@ class Sha1(object):
must be capitalized. encode and match methods must be provided and are
the only ones that will be used by swauth.
"""
def encode_w_salt(self, salt, key):
"""
Encodes a user key with salt into a particular format. The result of
this method will be used internally.
:param salt: Salt for hashing
:param key: User's secret key
:returns: A string representing user credentials
"""
enc_key = '%s%s' % (salt, key)
enc_val = hashlib.sha1(enc_key).hexdigest()
return "sha1:%s$%s" % (salt, enc_val)
def encode(self, key):
"""
Encodes a user key into a particular format. The result of this method
@ -88,9 +99,8 @@ class Sha1(object):
:param key: User's secret key
:returns: A string representing user credentials
"""
enc_key = '%s%s' % (self.salt, key)
enc_val = hashlib.sha1(enc_key).hexdigest()
return "sha1:%s$%s" % (self.salt, enc_val)
salt = os.urandom(32).encode('base64').rstrip();
return self.encode_w_salt(salt, key)
def match(self, key, creds):
"""
@ -100,4 +110,56 @@ class Sha1(object):
:param creds: User's stored credentials
:returns: True if the supplied key is valid, False otherwise
"""
return self.encode(key) == creds
[type, rest] = creds.split(':')
[salt, enc] = rest.split('$')
return self.encode_w_salt(salt, key) == creds
class Sha512(object):
"""
Provides a particular auth type for encoding format for encoding and
matching user keys.
This class must be all lowercase except for the first character, which
must be capitalized. encode and match methods must be provided and are
the only ones that will be used by swauth.
"""
def encode_w_salt(self, salt, key):
"""
Encodes a user key with salt into a particular format. The result of
this method will be used internal.
:param salt: Salt for hashing
:param key: User's secret key
:returns: A string representing user credentials
"""
enc_key = '%s%s' % (salt, key)
enc_val = hashlib.sha512(enc_key).hexdigest()
return "sha512:%s$%s" % (salt, enc_val)
def encode(self, key):
"""
Encodes a user key into a particular format. The result of this method
will be used by swauth for storing user credentials.
:param key: User's secret key
:returns: A string representing user credentials
"""
salt = os.urandom(32).encode('base64').rstrip();
return self.encode_w_salt(salt, key)
def match(self, key, creds):
"""
Checks whether the user-provided key matches the user's credentials
:param key: User-supplied key
:param creds: User's stored credentials
:returns: True if the supplied key is valid, False otherwise
"""
[type, rest] = creds.split(':')
[salt, enc] = rest.split('$')
return self.encode_w_salt(salt, key) == creds

View File

@ -140,7 +140,6 @@ class Swauth(object):
if self.auth_encoder is None:
raise Exception('Invalid auth_type in config file: %s'
% self.auth_type)
self.auth_encoder.salt = conf.get('auth_type_salt', 'swauthsalt')
self.allow_overrides = \
conf.get('allow_overrides', 't').lower() in TRUE_VALUES
self.agent = '%(orig)s Swauth'