Use proper randomization when generating new API keys.

Previously we were generating API keys deterministically using a hash
of the user's email address; this is clearly not a good long-term
approach.

(imported from commit 14d0c7c9edbc45b3ae1d17a43765ad9726338d4d)
This commit is contained in:
Tim Abbott 2013-05-28 17:59:55 -04:00
parent d92d62412f
commit abd9e4e635
6 changed files with 10 additions and 17 deletions

View File

@ -123,9 +123,8 @@ if DEPLOYED:
# cookie will slow down some attackers.
CSRF_COOKIE_PATH = '/;HttpOnly'
# Used just for generating initial passwords and API keys.
# Used just for generating initial passwords (only used in testing environments).
INITIAL_PASSWORD_SALT = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
INITIAL_API_KEY_SALT = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# A shared secret, used to authenticate different parts of the app to each other.
# FIXME: store this password more securely

View File

@ -2,7 +2,7 @@ from __future__ import absolute_import
from django.conf import settings
from zephyr.lib.initial_password import initial_password, initial_api_key
from zephyr.lib.initial_password import initial_password
from zephyr.models import Realm, Stream, UserProfile, Huddle, \
Subscription, Recipient, Client, Message, \
get_huddle_hash

View File

@ -3,11 +3,11 @@ from __future__ import absolute_import
from django.conf import settings
from django.contrib.auth.models import UserManager
from django.utils import timezone
from zephyr.lib.initial_password import initial_api_key
from zephyr.models import UserProfile, Recipient, Subscription
import base64
import hashlib
import simplejson
import random
# The ordered list of onboarding steps we want new users to complete. If the
# steps are changed here, they must also be changed in onboarding.js.
@ -37,7 +37,8 @@ def create_user_profile(realm, email, password, active, bot, full_name, short_na
else:
user_profile.set_password(password)
user_profile.api_key = initial_api_key(email)
# Generate a new, random API key
user_profile.api_key = base64.b64encode(hashlib.sha256( str(random.getrandbits(256))).digest())[0:32]
return user_profile
def create_user(email, password, realm, full_name, short_name,

View File

@ -6,16 +6,8 @@ import hashlib
import base64
def initial_password(email):
"""Given an email address, returns the initial password for that account, as
created by populate_db."""
digest = hashlib.sha256(settings.INITIAL_PASSWORD_SALT + email).digest()
return base64.b64encode(digest)[:16]
def initial_api_key(email):
"""Given an email address, returns the initial API key for that account"""
digest = hashlib.sha256(settings.INITIAL_API_KEY_SALT + email).digest()
return base64.b16encode(digest)[:32].lower()

View File

@ -1,7 +1,8 @@
from __future__ import absolute_import
from django.core.management.base import BaseCommand
from zephyr.lib.initial_password import initial_password, initial_api_key
from zephyr.lib.initial_password import initial_password
from zephyr.models import get_user_profile_by_email
class Command(BaseCommand):
help = "Print the initial password and API key for accounts as created by populate_db"
@ -14,4 +15,4 @@ class Command(BaseCommand):
if '@' not in email:
print 'ERROR: %s does not look like an email address' % (email,)
continue
print self.fmt % (email, initial_password(email), initial_api_key(email))
print self.fmt % (email, initial_password(email), get_user_profile_by_email(email).api_key)

View File

@ -11,7 +11,7 @@ from zephyr.models import Message, UserProfile, Stream, Recipient, Subscription,
PreregistrationUser, UserMessage
from zephyr.tornadoviews import json_get_updates, api_get_messages
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError
from zephyr.lib.initial_password import initial_password, initial_api_key
from zephyr.lib.initial_password import initial_password
from zephyr.lib.actions import do_send_message, gather_subscriptions, \
create_stream_if_needed, do_add_subscription
from zephyr.lib.bugdown import convert, emoji_list
@ -81,7 +81,7 @@ class AuthedTestCase(TestCase):
'terms': True})
def get_api_key(self, email):
return initial_api_key(email)
return self.get_user_profile(email).api_key
def get_user_profile(self, email):
"""