feat: use hmac, sha256, and a better secret for published nomcom hashes. (#4475)

* feat: use hmac, sha256, and a better secret for published nomcom hashes.

* fix: avoid using django secret key for a different secret context

* fix: Only strip the newline

* fix: improve readability by using rstrip
This commit is contained in:
Robert Sparks 2022-09-20 12:09:11 -05:00 committed by GitHub
parent 5d6f1e7509
commit 5c8545eecb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 8 deletions

View file

@ -1,9 +1,11 @@
# Copyright The IETF Trust 2012-2020, All Rights Reserved
# Copyright The IETF Trust 2012-2022, All Rights Reserved
# -*- coding: utf-8 -*-
import base64
import datetime
import hashlib
import hmac
import os
import re
import tempfile
@ -101,8 +103,7 @@ def get_user_email(user):
return user._email_cache
def get_hash_nominee_position(date, nominee_position_id):
return hashlib.md5(('%s%s%s' % (settings.SECRET_KEY, date, nominee_position_id)).encode('utf-8')).hexdigest()
return hmac.new(settings.NOMCOM_APP_SECRET, f"{date}{nominee_position_id}".encode('utf-8'), hashlib.sha256).hexdigest()
def initialize_templates_for_group(group):
for template_name in DEFAULT_NOMCOM_TEMPLATES:
@ -165,6 +166,8 @@ def delete_nomcom_templates(nomcom):
nomcom_template_path = '/nomcom/' + nomcom.group.acronym
DBTemplate.objects.filter(path__contains=nomcom_template_path).delete()
def command_line_safe_secret(secret):
return base64.encodebytes(secret).decode('utf-8').rstrip()
def retrieve_nomcom_private_key(request, year):
private_key = request.session.get('NOMCOM_PRIVATE_KEY_%s' % year, None)
@ -173,8 +176,13 @@ def retrieve_nomcom_private_key(request, year):
return private_key
command = "%s bf -d -in /dev/stdin -k \"%s\" -a"
code, out, error = pipe(command % (settings.OPENSSL_COMMAND,
settings.SECRET_KEY), private_key)
code, out, error = pipe(
command % (
settings.OPENSSL_COMMAND,
command_line_safe_secret(settings.NOMCOM_APP_SECRET)
),
private_key
)
if code != 0:
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
return out
@ -185,8 +193,13 @@ def store_nomcom_private_key(request, year, private_key):
request.session['NOMCOM_PRIVATE_KEY_%s' % year] = ''
else:
command = "%s bf -e -in /dev/stdin -k \"%s\" -a"
code, out, error = pipe(command % (settings.OPENSSL_COMMAND,
settings.SECRET_KEY), private_key)
code, out, error = pipe(
command % (
settings.OPENSSL_COMMAND,
command_line_safe_secret(settings.NOMCOM_APP_SECRET)
),
private_key
)
if code != 0:
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
if error:

View file

@ -6,6 +6,7 @@ import datetime
import re
from collections import OrderedDict, Counter
import csv
import hmac
from django.conf import settings
from django.contrib import messages
@ -695,7 +696,7 @@ def private_questionnaire(request, year):
def process_nomination_status(request, year, nominee_position_id, state, date, hash):
valid = get_hash_nominee_position(date, nominee_position_id) == hash
valid = hmac.compare_digest(get_hash_nominee_position(date, nominee_position_id), hash)
if not valid:
permission_denied(request, "Bad hash!")
expiration_days = getattr(settings, 'DAYS_TO_EXPIRE_NOMINATION_LINK', None)

View file

@ -1272,6 +1272,8 @@ if SERVER_MODE != 'production':
if 'SECRET_KEY' not in locals():
SECRET_KEY = 'PDwXboUq!=hPjnrtG2=ge#N$Dwy+wn@uivrugwpic8mxyPfHka'
if 'NOMCOM_APP_SECRET' not in locals():
NOMCOM_APP_SECRET = b'\x9b\xdas1\xec\xd5\xa0SI~\xcb\xd4\xf5t\x99\xc4i\xd7\x9f\x0b\xa9\xe8\xfeY\x80$\x1e\x12tN:\x84'
ALLOWED_HOSTS = ['*',]