mirror of
https://github.com/nicolargo/glances.git
synced 2024-11-28 14:12:21 +03:00
Use of a broken or weak cryptographic hashing algorithm (SHA256) on password storage #2175
This commit is contained in:
commit
6876490d24
@ -75,7 +75,7 @@ class GlancesClientBrowser(object):
|
||||
# Try with the preconfigure password (only if status is PROTECTED)
|
||||
clear_password = self.password.get_password(server['name'])
|
||||
if clear_password is not None:
|
||||
server['password'] = self.password.sha256_hash(clear_password)
|
||||
server['password'] = self.password.get_hash(clear_password)
|
||||
return 'http://{}:{}@{}:{}'.format(server['username'], server['password'], server['ip'], server['port'])
|
||||
else:
|
||||
return 'http://{}:{}'.format(server['ip'], server['port'])
|
||||
@ -151,7 +151,7 @@ class GlancesClientBrowser(object):
|
||||
)
|
||||
# Store the password for the selected server
|
||||
if clear_password is not None:
|
||||
self.set_in_selected('password', self.password.sha256_hash(clear_password))
|
||||
self.set_in_selected('password', self.password.get_hash(clear_password))
|
||||
|
||||
# Display the Glance client on the selected server
|
||||
logger.info("Connect Glances client to the {} server".format(server['key']))
|
||||
|
@ -68,6 +68,10 @@ if PY3:
|
||||
return s.decode()
|
||||
return s.encode('ascii', 'ignore').decode()
|
||||
|
||||
def to_hex(s):
|
||||
"""Convert the bytes string to a hex string"""
|
||||
return s.hex()
|
||||
|
||||
def listitems(d):
|
||||
return list(d.items())
|
||||
|
||||
@ -166,6 +170,10 @@ else:
|
||||
return s
|
||||
return unicodedata.normalize('NFKD', s).encode('ascii', 'ignore')
|
||||
|
||||
def to_hex(s):
|
||||
"""Convert the string to a hex string in Python 2"""
|
||||
return s.encode('hex')
|
||||
|
||||
def listitems(d):
|
||||
return d.items()
|
||||
|
||||
|
@ -127,8 +127,10 @@ class GlancesBottle(object):
|
||||
if username == self.args.username:
|
||||
from glances.password import GlancesPassword
|
||||
|
||||
pwd = GlancesPassword(username=username, config=self.config)
|
||||
return pwd.check_password(self.args.password, pwd.sha256_hash(password))
|
||||
pwd = GlancesPassword(username=username,
|
||||
config=self.config)
|
||||
return pwd.check_password(self.args.password,
|
||||
pwd.get_hash(password))
|
||||
else:
|
||||
return False
|
||||
|
||||
|
12
glances/outputs/static/public/glances.js
vendored
12
glances/outputs/static/public/glances.js
vendored
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ import sys
|
||||
import uuid
|
||||
from io import open
|
||||
|
||||
from glances.compat import b, input
|
||||
from glances.compat import b, input, to_hex
|
||||
from glances.config import user_config_dir
|
||||
from glances.globals import safe_makedirs
|
||||
from glances.logger import logger
|
||||
@ -36,25 +36,26 @@ class GlancesPassword(object):
|
||||
|
||||
def local_password_path(self):
|
||||
"""Return the local password path.
|
||||
Related toissue: Password files in same configuration dir in effect #2143
|
||||
Related to issue: Password files in same configuration dir in effect #2143
|
||||
"""
|
||||
if self.config is None:
|
||||
return user_config_dir()
|
||||
else:
|
||||
return self.config.get_value('passwords', 'local_password_path', default=user_config_dir())
|
||||
|
||||
def sha256_hash(self, plain_password):
|
||||
"""Return the SHA-256 of the given password."""
|
||||
return hashlib.sha256(b(plain_password)).hexdigest()
|
||||
|
||||
def get_hash(self, salt, plain_password):
|
||||
"""Return the hashed password, salt + SHA-256."""
|
||||
return hashlib.sha256(salt.encode() + plain_password.encode()).hexdigest()
|
||||
def get_hash(self, plain_password, salt=''):
|
||||
"""Return the hashed password, salt + pbkdf2_hmac."""
|
||||
return to_hex(hashlib.pbkdf2_hmac('sha256',
|
||||
plain_password.encode(),
|
||||
salt.encode(),
|
||||
100000,
|
||||
dklen=128))
|
||||
|
||||
def hash_password(self, plain_password):
|
||||
"""Hash password with a salt based on UUID (universally unique identifier)."""
|
||||
salt = uuid.uuid4().hex
|
||||
encrypted_password = self.get_hash(salt, plain_password)
|
||||
encrypted_password = self.get_hash(plain_password,
|
||||
salt=salt)
|
||||
return salt + '$' + encrypted_password
|
||||
|
||||
def check_password(self, hashed_password, plain_password):
|
||||
@ -63,7 +64,8 @@ class GlancesPassword(object):
|
||||
Return the comparison with the encrypted_password.
|
||||
"""
|
||||
salt, encrypted_password = hashed_password.split('$')
|
||||
re_encrypted_password = self.get_hash(salt, plain_password)
|
||||
re_encrypted_password = self.get_hash(plain_password,
|
||||
salt = salt)
|
||||
return encrypted_password == re_encrypted_password
|
||||
|
||||
def get_password(self, description='', confirm=False, clear=False):
|
||||
@ -72,11 +74,11 @@ class GlancesPassword(object):
|
||||
For Glances server, get the password (confirm=True, clear=False):
|
||||
1) from the password file (if it exists)
|
||||
2) from the CLI
|
||||
Optionally: save the password to a file (hashed with salt + SHA-256)
|
||||
Optionally: save the password to a file (hashed with salt + SHA-pbkdf2_hmac)
|
||||
|
||||
For Glances client, get the password (confirm=False, clear=True):
|
||||
1) from the CLI
|
||||
2) the password is hashed with SHA-256 (only SHA string transit
|
||||
2) the password is hashed with SHA-pbkdf2_hmac (only SHA string transit
|
||||
through the network)
|
||||
"""
|
||||
if os.path.exists(self.password_file) and not clear:
|
||||
@ -84,21 +86,21 @@ class GlancesPassword(object):
|
||||
logger.info("Read password from file {}".format(self.password_file))
|
||||
password = self.load_password()
|
||||
else:
|
||||
# password_sha256 is the plain SHA-256 password
|
||||
# password_hashed is the salt + SHA-256 password
|
||||
password_sha256 = self.sha256_hash(getpass.getpass(description))
|
||||
password_hashed = self.hash_password(password_sha256)
|
||||
# password_hash is the plain SHA-pbkdf2_hmac password
|
||||
# password_hashed is the salt + SHA-pbkdf2_hmac password
|
||||
password_hash = self.get_hash(getpass.getpass(description))
|
||||
password_hashed = self.hash_password(password_hash)
|
||||
if confirm:
|
||||
# password_confirm is the clear password (only used to compare)
|
||||
password_confirm = self.sha256_hash(getpass.getpass('Password (confirm): '))
|
||||
password_confirm = self.get_hash(getpass.getpass('Password (confirm): '))
|
||||
|
||||
if not self.check_password(password_hashed, password_confirm):
|
||||
logger.critical("Sorry, passwords do not match. Exit.")
|
||||
sys.exit(1)
|
||||
|
||||
# Return the plain SHA-256 or the salted password
|
||||
# Return the plain SHA-pbkdf2_hmac or the salted password
|
||||
if clear:
|
||||
password = password_sha256
|
||||
password = password_hash
|
||||
else:
|
||||
password = password_hashed
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user