1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-04-27 11:01:14 +00:00

fix Use of a broken or weak cryptographic hashing (#7671)

Co-authored-by: lian <imwhatiam123@gmail.com>
This commit is contained in:
seafile-dev 2025-03-29 13:16:01 +08:00 committed by GitHub
parent c8026ddb6c
commit 5eb303c76b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 8 additions and 131 deletions

View File

@ -252,7 +252,7 @@ class ResetPasswordView(APIView):
user.save()
if not request.session.is_empty():
# update session auth hash
# invalidate all active sessions after change password.
update_session_auth_hash(request, request.user)
return Response({'success': True})

View File

@ -1,46 +1,15 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import hashlib
import logging
from registration.signals import user_deleted
from django.db import models
from django.conf import settings
from django.dispatch import receiver
from django.utils.encoding import smart_str
from django.db.models.manager import EmptyManager
logger = logging.getLogger(__name__)
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):
pass

View File

@ -670,13 +670,6 @@ class User(object):
Returns a boolean of whether the raw_password was correct. Handles
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)
def set_unusable_password(self):

View File

@ -11,6 +11,9 @@ PASSWORD_HASH_KEY = getattr(settings, 'PASSWORD_SESSION_PASSWORD_HASH_KEY', 'pas
def get_password_hash(user):
"""Returns a string of crypted password hash"""
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(
md5(password.encode()).hexdigest().encode() + settings.SECRET_KEY.encode()
).hexdigest()

View File

@ -115,7 +115,10 @@ class RegistrationManager(models.Manager):
username = user.username
if isinstance(username, str):
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,
activation_key=activation_key)

View File

@ -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()