mirror of
https://github.com/haiwen/seahub.git
synced 2025-07-12 14:38:58 +00:00
fix Use of a broken or weak cryptographic hashing (#7671)
Co-authored-by: lian <imwhatiam123@gmail.com>
This commit is contained in:
parent
c8026ddb6c
commit
5eb303c76b
@ -252,7 +252,7 @@ class ResetPasswordView(APIView):
|
|||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
if not request.session.is_empty():
|
if not request.session.is_empty():
|
||||||
# update session auth hash
|
# invalidate all active sessions after change password.
|
||||||
update_session_auth_hash(request, request.user)
|
update_session_auth_hash(request, request.user)
|
||||||
|
|
||||||
return Response({'success': True})
|
return Response({'success': True})
|
||||||
|
@ -1,46 +1,15 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
import hashlib
|
|
||||||
import logging
|
import logging
|
||||||
from registration.signals import user_deleted
|
from registration.signals import user_deleted
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.encoding import smart_str
|
|
||||||
from django.db.models.manager import EmptyManager
|
from django.db.models.manager import EmptyManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
UNUSABLE_PASSWORD = '!' # This will never be a valid hash
|
||||||
|
|
||||||
|
|
||||||
def get_hexdigest(algorithm, salt, raw_password):
|
|
||||||
"""
|
|
||||||
Returns a string of the hexdigest of the given plaintext password and salt
|
|
||||||
using the given algorithm ('md5', 'sha1' or 'crypt').
|
|
||||||
"""
|
|
||||||
raw_password, salt = smart_str(raw_password).encode('utf-8'), smart_str(salt).encode('utf-8')
|
|
||||||
if algorithm == 'crypt':
|
|
||||||
try:
|
|
||||||
import crypt
|
|
||||||
except ImportError:
|
|
||||||
raise ValueError('"crypt" password algorithm not supported in this environment')
|
|
||||||
return crypt.crypt(raw_password, salt)
|
|
||||||
|
|
||||||
if algorithm == 'md5':
|
|
||||||
return hashlib.md5(salt + raw_password).hexdigest()
|
|
||||||
elif algorithm == 'sha1':
|
|
||||||
return hashlib.sha1(salt + raw_password).hexdigest()
|
|
||||||
raise ValueError("Got unknown password algorithm type in password.")
|
|
||||||
|
|
||||||
|
|
||||||
def check_password(raw_password, enc_password):
|
|
||||||
"""
|
|
||||||
Returns a boolean of whether the raw_password was correct. Handles
|
|
||||||
encryption formats behind the scenes.
|
|
||||||
"""
|
|
||||||
algo, salt, hsh = enc_password.split('$')
|
|
||||||
return hsh == get_hexdigest(algo, salt, raw_password)
|
|
||||||
|
|
||||||
|
|
||||||
class SiteProfileNotAvailable(Exception):
|
class SiteProfileNotAvailable(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -670,13 +670,6 @@ class User(object):
|
|||||||
Returns a boolean of whether the raw_password was correct. Handles
|
Returns a boolean of whether the raw_password was correct. Handles
|
||||||
encryption formats behind the scenes.
|
encryption formats behind the scenes.
|
||||||
"""
|
"""
|
||||||
# Backwards-compatibility check. Older passwords won't include the
|
|
||||||
# algorithm or salt.
|
|
||||||
|
|
||||||
# if '$' not in self.password:
|
|
||||||
# is_correct = (self.password == \
|
|
||||||
# get_hexdigest('sha1', '', raw_password))
|
|
||||||
# return is_correct
|
|
||||||
return (ccnet_threaded_rpc.validate_emailuser(self.username, raw_password) == 0)
|
return (ccnet_threaded_rpc.validate_emailuser(self.username, raw_password) == 0)
|
||||||
|
|
||||||
def set_unusable_password(self):
|
def set_unusable_password(self):
|
||||||
|
@ -11,6 +11,9 @@ PASSWORD_HASH_KEY = getattr(settings, 'PASSWORD_SESSION_PASSWORD_HASH_KEY', 'pas
|
|||||||
def get_password_hash(user):
|
def get_password_hash(user):
|
||||||
"""Returns a string of crypted password hash"""
|
"""Returns a string of crypted password hash"""
|
||||||
password = user.enc_password or ''
|
password = user.enc_password or ''
|
||||||
|
# To achieve "invalidate all active sessions after change password",
|
||||||
|
# a hash value generated based on the user password is stored in the session,
|
||||||
|
# and compare it for each request in the MIDDLEWARE.
|
||||||
return md5(
|
return md5(
|
||||||
md5(password.encode()).hexdigest().encode() + settings.SECRET_KEY.encode()
|
md5(password.encode()).hexdigest().encode() + settings.SECRET_KEY.encode()
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
|
@ -115,7 +115,10 @@ class RegistrationManager(models.Manager):
|
|||||||
username = user.username
|
username = user.username
|
||||||
if isinstance(username, str):
|
if isinstance(username, str):
|
||||||
username = username.encode('utf-8')
|
username = username.encode('utf-8')
|
||||||
activation_key = hashlib.sha1(salt+username).hexdigest()
|
|
||||||
|
# Take the first 16 character to avoid errors.
|
||||||
|
# (1406, "Data too long for column 'activation_key' at row 1")
|
||||||
|
activation_key = hashlib.sha256(salt+username).hexdigest()[:16]
|
||||||
return self.create(emailuser_id=user.id,
|
return self.create(emailuser_id=user.id,
|
||||||
activation_key=activation_key)
|
activation_key=activation_key)
|
||||||
|
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import hashlib
|
|
||||||
import getpass
|
|
||||||
|
|
||||||
# Get .ccnet directory from argument or user input
|
|
||||||
if len(sys.argv) >= 2:
|
|
||||||
ccnet_dir = sys.argv[1]
|
|
||||||
else:
|
|
||||||
home_dir = os.path.join(os.path.expanduser('~'), '.ccnet')
|
|
||||||
ccnet_dir = input("Enter ccnet directory:(leave blank for %s) " % home_dir)
|
|
||||||
if not ccnet_dir:
|
|
||||||
ccnet_dir = home_dir
|
|
||||||
|
|
||||||
# Test usermgr.db exists
|
|
||||||
usermgr_db = os.path.join(ccnet_dir, 'PeerMgr/usermgr.db')
|
|
||||||
if not os.path.exists(usermgr_db):
|
|
||||||
print('%s DOES NOT exist. FAILED' % usermgr_db)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Connect db
|
|
||||||
conn = sqlite3.connect(usermgr_db)
|
|
||||||
|
|
||||||
# Get cursor
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
# Check whether admin user exists
|
|
||||||
sql = "SELECT email FROM EmailUser WHERE is_staff = 1"
|
|
||||||
try:
|
|
||||||
c.execute(sql)
|
|
||||||
except sqlite3.Error as e:
|
|
||||||
print("An error orrured:", e.args[0])
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
staff_list = c.fetchall()
|
|
||||||
if staff_list:
|
|
||||||
print("Admin is already in database. Email as follows: ")
|
|
||||||
print('--------------------')
|
|
||||||
for e in staff_list:
|
|
||||||
print(e[0])
|
|
||||||
print('--------------------')
|
|
||||||
choice = input('Previous admin would be deleted, would you like to continue?[y/n] ')
|
|
||||||
if choice == 'y':
|
|
||||||
sql = "DELETE FROM EmailUser WHERE is_staff = 1"
|
|
||||||
try:
|
|
||||||
c.execute(sql)
|
|
||||||
except sqlite3.Error as e:
|
|
||||||
print("An error orrured:", e.args[0])
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
print('Previous admin is deleted.')
|
|
||||||
else:
|
|
||||||
conn.close()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# Create admin user
|
|
||||||
choice = input('Would you like to create admin user?[y/n]')
|
|
||||||
if choice != 'y':
|
|
||||||
conn.close()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
username = input('E-mail address:')
|
|
||||||
passwd = getpass.getpass('Password:')
|
|
||||||
passwd2 = getpass.getpass('Password (again):')
|
|
||||||
if passwd != passwd2:
|
|
||||||
print("Two passwords NOT same.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
mySha1 = hashlib.sha1()
|
|
||||||
mySha1.update(passwd.encode('utf-8'))
|
|
||||||
enc_passwd = mySha1.hexdigest()
|
|
||||||
sql = "INSERT INTO EmailUser(email, passwd, is_staff, is_active, ctime) VALUES ('%s', '%s', 1, 1, '%d');" % (username, enc_passwd, time.time()*1000000)
|
|
||||||
try:
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute(sql)
|
|
||||||
conn.commit()
|
|
||||||
except sqlite3.Error as e:
|
|
||||||
print("An error occured:", e.args[0])
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
print("Admin user created successfully.")
|
|
||||||
|
|
||||||
# Close db
|
|
||||||
conn.close()
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user