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:
parent
5d6f1e7509
commit
5c8545eecb
|
@ -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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import hmac
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -101,8 +103,7 @@ def get_user_email(user):
|
||||||
return user._email_cache
|
return user._email_cache
|
||||||
|
|
||||||
def get_hash_nominee_position(date, nominee_position_id):
|
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):
|
def initialize_templates_for_group(group):
|
||||||
for template_name in DEFAULT_NOMCOM_TEMPLATES:
|
for template_name in DEFAULT_NOMCOM_TEMPLATES:
|
||||||
|
@ -165,6 +166,8 @@ def delete_nomcom_templates(nomcom):
|
||||||
nomcom_template_path = '/nomcom/' + nomcom.group.acronym
|
nomcom_template_path = '/nomcom/' + nomcom.group.acronym
|
||||||
DBTemplate.objects.filter(path__contains=nomcom_template_path).delete()
|
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):
|
def retrieve_nomcom_private_key(request, year):
|
||||||
private_key = request.session.get('NOMCOM_PRIVATE_KEY_%s' % year, None)
|
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
|
return private_key
|
||||||
|
|
||||||
command = "%s bf -d -in /dev/stdin -k \"%s\" -a"
|
command = "%s bf -d -in /dev/stdin -k \"%s\" -a"
|
||||||
code, out, error = pipe(command % (settings.OPENSSL_COMMAND,
|
code, out, error = pipe(
|
||||||
settings.SECRET_KEY), private_key)
|
command % (
|
||||||
|
settings.OPENSSL_COMMAND,
|
||||||
|
command_line_safe_secret(settings.NOMCOM_APP_SECRET)
|
||||||
|
),
|
||||||
|
private_key
|
||||||
|
)
|
||||||
if code != 0:
|
if code != 0:
|
||||||
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
|
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
|
||||||
return out
|
return out
|
||||||
|
@ -185,8 +193,13 @@ def store_nomcom_private_key(request, year, private_key):
|
||||||
request.session['NOMCOM_PRIVATE_KEY_%s' % year] = ''
|
request.session['NOMCOM_PRIVATE_KEY_%s' % year] = ''
|
||||||
else:
|
else:
|
||||||
command = "%s bf -e -in /dev/stdin -k \"%s\" -a"
|
command = "%s bf -e -in /dev/stdin -k \"%s\" -a"
|
||||||
code, out, error = pipe(command % (settings.OPENSSL_COMMAND,
|
code, out, error = pipe(
|
||||||
settings.SECRET_KEY), private_key)
|
command % (
|
||||||
|
settings.OPENSSL_COMMAND,
|
||||||
|
command_line_safe_secret(settings.NOMCOM_APP_SECRET)
|
||||||
|
),
|
||||||
|
private_key
|
||||||
|
)
|
||||||
if code != 0:
|
if code != 0:
|
||||||
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
|
log("openssl error: %s:\n Error %s: %s" %(command, code, error))
|
||||||
if error:
|
if error:
|
||||||
|
|
|
@ -6,6 +6,7 @@ import datetime
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict, Counter
|
from collections import OrderedDict, Counter
|
||||||
import csv
|
import csv
|
||||||
|
import hmac
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
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):
|
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:
|
if not valid:
|
||||||
permission_denied(request, "Bad hash!")
|
permission_denied(request, "Bad hash!")
|
||||||
expiration_days = getattr(settings, 'DAYS_TO_EXPIRE_NOMINATION_LINK', None)
|
expiration_days = getattr(settings, 'DAYS_TO_EXPIRE_NOMINATION_LINK', None)
|
||||||
|
|
|
@ -1272,6 +1272,8 @@ if SERVER_MODE != 'production':
|
||||||
|
|
||||||
if 'SECRET_KEY' not in locals():
|
if 'SECRET_KEY' not in locals():
|
||||||
SECRET_KEY = 'PDwXboUq!=hPjnrtG2=ge#N$Dwy+wn@uivrugwpic8mxyPfHka'
|
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 = ['*',]
|
ALLOWED_HOSTS = ['*',]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue