Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport 2.10.0 changes #7230

Merged
merged 18 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -239,19 +239,7 @@ rust-audit:

securedrop/config.py: ## Generate the test SecureDrop application config.
@echo "███ Generating securedrop/config.py..."
@cd securedrop && source_secret_key=$(shell head -c 32 /dev/urandom | base64) \
journalist_secret_key=$(shell head -c 32 /dev/urandom | base64) \
scrypt_id_pepper=$(shell head -c 32 /dev/urandom | base64) \
scrypt_gpg_pepper=$(shell head -c 32 /dev/urandom | base64) \
python -c 'import os; from jinja2 import Environment, FileSystemLoader; \
env = Environment(loader=FileSystemLoader(".")); \
ctx = {"securedrop_app_gpg_fingerprint": "65A1B5FF195B56353CC63DFFCC40EF1228271441"}; \
ctx.update(dict((k, {"stdout":v}) for k,v in os.environ.items())); \
ctx = open("config.py", "w").write(env.get_template("config.py.example").render(ctx))'
@echo >> securedrop/config.py
@echo "SUPPORTED_LOCALES = $$(make --quiet supported-locales)" >> securedrop/config.py
@echo "SUPPORTED_LOCALES.append('en_US')" >> securedrop/config.py
@echo
@./securedrop/bin/dev-config

HOOKS_DIR=.githooks

Expand Down
31 changes: 30 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
# Changelog

## 2.10.0~rc1
## 2.10.0

This release contains fixes for issues described in the most recent security audit by 7A Security, see
our [blog post](https://securedrop.org/news/securedrop-2_10_0-released/) for more details. It also contains other maintenance fixes.

### Security

* Don't allow admins to look up arbitrary users' TOTP secrets via the web (SEC-01-001 WP4)
* Validate user provided same password back to server (SEC-01-002 WP4)
* Require POST requests for `/logout` for CSRF protection (SEC-01-003 WP4)
* Set password for redis access (SEC-01-008 WP3)
* Set `SameSite=Strict` on all cookies for more CSRF protection

### Web applications
* Dependency updates:
* sequoia-openpgp (Rust crate) from 1.20.0 to 1.21.1 (#7197)
* setuptools from 56.0.0 to 70.3.0 for CVE-2024-6345 (#7205, #7214)
* openssl (Rust crate) from 0.10.60 to 0.10.66 for RUSTSEC-2024-0357 (#7206)

### Journalist Workstation
* Dependency updates:
* setuptools from 56.0.0 to 70.3.0 for CVE-2024-6345 (#7205, #7214)
* Remove d2to1 and pbr (#7205)

### Development
* Don't point people to the decommissioned SecureDrop forum (#7204)
* Migrate all CI jobs to GitHub Actions (#7216, #7217, #7218, #7219, #7220, #7222, #7223)
* Improve staging job by using upstream gcloud-sdk image and enforcing GCE VM lifespan (#7215, #7224)
* Dependency updates:
* certifi from 2023.7.22 to 2024.7.4 for CVE-2024-39689 (#7199)
* Remove pytest-catchlog (#7199)

## 2.9.0

Expand Down
2 changes: 1 addition & 1 deletion install_files/ansible-base/group_vars/all/securedrop
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Variables that apply to both the app and monitor server go in this file
# If the monitor or app server need different values define the variable in
# hosts_vars/app.yml or host_vars/mon.yml
securedrop_version: "2.10.0~rc1"
securedrop_version: "2.10.0"
securedrop_app_code_sdist_name: "securedrop-app-code-{{ securedrop_version | replace('~', '-') }}.tar.gz"

grsecurity: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,48 @@
tags:
- securedrop_config

- name: Generate 32-byte value for "redis password".
shell: "head -c 32 /dev/urandom | base64"
register: redis_password
when: not config.stat.exists
tags:
- securedrop_config

- name: Add 32-byte value for "redis password" to config.py.
lineinfile:
dest: "{{ securedrop_code }}/config.py"
regexp: "redis_password"
line: "REDIS_PASSWORD = '{{ redis_password.stdout }}'"
when: not config.stat.exists
tags:
- securedrop_config

- name: Create rq_config.py with the redis password
copy:
content: "REDIS_PASSWORD = \"{{ redis_password.stdout }}\""
dest: "{{ securedrop_code }}/rq_config.py"
owner: "root"
group: "www-data"
mode: "0640"
when: not config.stat.exists
tags:
- securedrop_config

- name: Add 32-byte value for "redis password" to /etc/redis/redis.conf.
lineinfile:
dest: "/etc/redis/redis.conf"
regexp: "^requirepass"
line: "requirepass {{ redis_password.stdout }}"
insertafter: EOF
when: not config.stat.exists
register: redis_conf

- name: Restart redis
service:
name: redis-server
state: restarted
when: redis_conf.changed

- name: Declare Application GPG fingerprint in config.py.
lineinfile:
dest: "{{ securedrop_code }}/config.py"
Expand Down
2 changes: 1 addition & 1 deletion molecule/shared/stable.ver
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.9.0
2.10.0
2 changes: 1 addition & 1 deletion molecule/testinfra/app-code/test_securedrop_rqworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_securedrop_rqworker_service(host):
securedrop_test_vars.securedrop_code,
securedrop_test_vars.securedrop_venv_site_packages,
),
f"ExecStart={securedrop_test_vars.securedrop_venv_bin}/rqworker",
f"ExecStart={securedrop_test_vars.securedrop_venv_bin}/rqworker -c rq_config",
"PrivateDevices=yes",
"PrivateTmp=yes",
"ProtectSystem=full",
Expand Down
38 changes: 38 additions & 0 deletions molecule/testinfra/app/test_redis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Test redis is configured as desired
"""

import re

import testutils

sdvars = testutils.securedrop_test_vars
testinfra_hosts = [sdvars.app_hostname]


def test_auth_required(host):
"""
Verify the redis server requires authentication
"""
response = host.run("bash -c 'echo \"PING\" | redis-cli'").stdout.strip()
assert response == "NOAUTH Authentication required."


def test_password_works(host):
"""
Verify the redis password works
"""
f = host.file("/var/www/securedrop/rq_config.py")
with host.sudo():
# First let's check file permissions
assert f.is_file
assert f.user == "root"
assert f.group == "www-data"
assert f.mode == 0o640
contents = f.content_string
password = re.search('"(.*?)"', contents).group(1)
# Now run an authenticated PING
response = host.run(
f'bash -c \'echo "PING" | REDISCLI_AUTH="{password}" redis-cli\''
).stdout.strip()
assert response == "PONG"
1 change: 1 addition & 0 deletions securedrop/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Don't version control config.py because it contains secret values
config.py
rq_config.py

# compiled file
securedrop-adminc
Expand Down
34 changes: 34 additions & 0 deletions securedrop/bin/dev-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
import os
import base64
import subprocess

from jinja2 import Environment, FileSystemLoader


def generate_random(length):
# Emulate the {"stdout": "..."} dictionaries Ansible produces when configuring non-development environments.
return {'stdout': base64.b64encode(os.urandom(length)).decode()}


env = Environment(loader=FileSystemLoader("."))

ctx = {
"securedrop_app_gpg_fingerprint": "65A1B5FF195B56353CC63DFFCC40EF1228271441",
'source_secret_key': generate_random(32),
'journalist_secret_key': generate_random(32),
'scrypt_id_pepper': generate_random(32),
'scrypt_gpg_pepper': generate_random(32),
'redis_password': generate_random(32),
}

with open('securedrop/config.py', 'w') as f:
text = env.get_template("securedrop/config.py.example").render(ctx)
text += '\n'
supported_locales = subprocess.check_output(['make', '--quiet', 'supported-locales']).decode().strip()
text += f'SUPPORTED_LOCALES = {supported_locales}\n'
text += 'SUPPORTED_LOCALES.append("en_US")\n'
f.write(text)

with open('securedrop/rq_config.py', 'w') as f:
f.write('REDIS_PASSWORD = "{}"\n'.format(ctx['redis_password']['stdout']))
7 changes: 6 additions & 1 deletion securedrop/bin/dev-deps
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ function run_xvfb() {

function run_redis() {
rm -f "${REPOROOT}/securedrop/dump.rdb"
setsid redis-server >& /tmp/redis.out || cat /tmp/redis.out
redis_password=$(cd "${REPOROOT}/securedrop" && python -c "import rq_config; print(rq_config.REDIS_PASSWORD)")
echo "$redis_password" > /tmp/redispasswd
echo "requirepass ${redis_password}" | sudo -u redis tee -a /etc/redis/redis.conf
echo "Starting redis..."
sudo service redis-server start
}

function setup_vncauth {
Expand All @@ -47,6 +51,7 @@ function append_to_exit() {
function maybe_create_config_py() {
if ! test -f "${REPOROOT}/securedrop/config.py" ; then
append_to_exit "rm ${REPOROOT}/securedrop/config.py"
append_to_exit "rm ${REPOROOT}/securedrop/rq_config.py"
(cd "$REPOROOT" && make test-config)
fi
}
Expand Down
2 changes: 1 addition & 1 deletion securedrop/bin/generate-docs-screenshots
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ source "${BASH_SOURCE%/*}/dev-deps"

run_xvfb &
run_tor &
run_redis &
run_x11vnc &
urandom
build_redwood
maybe_create_config_py
run_redis

pybabel compile --directory translations/
pytest -v --page-layout "${@:-tests/functional/pageslayout}"
4 changes: 2 additions & 2 deletions securedrop/bin/run
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ cd "${REPOROOT}/securedrop"
source /opt/venvs/securedrop-app-code/bin/activate
source "${BASH_SOURCE%/*}/dev-deps"

run_redis &
urandom
build_redwood
maybe_create_config_py
run_redis
reset_demo
maybe_use_tor

# run the batch processing services normally managed by systemd
/opt/venvs/securedrop-app-code/bin/rqworker &
PYTHONPATH="${REPOROOT}/securedrop" /opt/venvs/securedrop-app-code/bin/rqworker -c rq_config &
PYTHONPATH="${REPOROOT}/securedrop" /opt/venvs/securedrop-app-code/bin/python "${REPOROOT}/securedrop/scripts/rqrequeue" --interval 60 &
PYTHONPATH="${REPOROOT}/securedrop" /opt/venvs/securedrop-app-code/bin/python "${REPOROOT}/securedrop/scripts/shredder" --interval 60 &
PYTHONPATH="${REPOROOT}/securedrop" /opt/venvs/securedrop-app-code/bin/python "${REPOROOT}/securedrop/scripts/source_deleter" --interval 10 &
Expand Down
2 changes: 1 addition & 1 deletion securedrop/bin/run-test
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ source "${BASH_SOURCE%/*}/dev-deps"

run_xvfb
run_tor &
run_redis &
setup_vncauth
run_x11vnc &
urandom
build_redwood
maybe_create_config_py
run_redis

if [ -n "${CIRCLE_BRANCH:-}" ] ; then
touch tests/log/firefox.log
Expand Down
2 changes: 1 addition & 1 deletion securedrop/bin/translation-test
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ source "${BASH_SOURCE%/*}/dev-deps"

run_xvfb
run_tor &
run_redis &
setup_vncauth
run_x11vnc &
urandom
build_redwood
maybe_create_config_py
run_redis
pybabel compile --directory translations/

mkdir -p "/tmp/test-results/logs"
Expand Down
2 changes: 2 additions & 0 deletions securedrop/config.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,5 @@ DEFAULT_LOCALE = 'en_US'

# How long a session is valid before it expires and logs a user out
SESSION_EXPIRATION_MINUTES = 120

REDIS_PASSWORD = '{{ redis_password.stdout }}'
7 changes: 5 additions & 2 deletions securedrop/debian/app-code/etc/apparmor.d/usr.sbin.apache2
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,13 @@
/var/www/securedrop/journalist_templates/_sources_confirmation_final_modal.html r,
/var/www/securedrop/journalist_templates/_sources_confirmation_modal.html r,
/var/www/securedrop/journalist_templates/account_edit_hotp_secret.html r,
/var/www/securedrop/journalist_templates/account_new_two_factor.html r,
/var/www/securedrop/journalist_templates/account_new_two_factor_totp.html r,
/var/www/securedrop/journalist_templates/account_new_two_factor_hotp.html r,
/var/www/securedrop/journalist_templates/admin.html r,
/var/www/securedrop/journalist_templates/admin_add_user.html r,
/var/www/securedrop/journalist_templates/admin_edit_hotp_secret.html r,
/var/www/securedrop/journalist_templates/admin_new_user_two_factor.html r,
/var/www/securedrop/journalist_templates/admin_new_user_two_factor_totp.html r,
/var/www/securedrop/journalist_templates/admin_new_user_two_factor_hotp.html r,
/var/www/securedrop/journalist_templates/base.html r,
/var/www/securedrop/journalist_templates/col.html r,
/var/www/securedrop/journalist_templates/config.html r,
Expand All @@ -213,6 +215,7 @@
/var/www/securedrop/pretty_bad_protocol/_meta.py r,
/var/www/securedrop/request_that_secures_file_uploads.py r,
/var/www/securedrop/rm.py r,
/var/www/securedrop/rq_config.py r,
/var/www/securedrop/sdconfig.py r,
/var/www/securedrop/secure_tempfile.py r,
/var/www/securedrop/source.py r,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Wants=redis-server.service

[Service]
Environment=PYTHONPATH="/var/www/securedrop:/opt/venvs/securedrop-app-code/lib/python3.8/site-packages"
ExecStart=/opt/venvs/securedrop-app-code/bin/rqworker
ExecStart=/opt/venvs/securedrop-app-code/bin/rqworker -c rq_config
PrivateDevices=yes
PrivateTmp=yes
ProtectSystem=full
Expand Down
8 changes: 7 additions & 1 deletion securedrop/debian/changelog
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
securedrop (2.10.0+focal) focal; urgency=medium

* see changelog.md

-- SecureDrop Team <[email protected]> Tue, 17 Sep 2024 16:05:58 -0400

securedrop (2.10.0~rc1+focal) focal; urgency=medium

* see changelog.md

-- SecureDrop Team <[email protected]> Fri, 28 Jun 2024 11:37:37 -0400
-- SecureDrop Team <[email protected]> Thu, 29 Aug 2024 14:42:38 -0700

securedrop (2.9.0+focal) focal; urgency=medium

Expand Down
25 changes: 24 additions & 1 deletion securedrop/debian/securedrop-app-code.postinst
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,22 @@ export_journalist_public_key() {

}

# Password-protect access to Redis
set_redis_password() {
# Only run when upgrading, which means config.py exists and rq_config.py does not.
if ! test -f "/var/www/securedrop/rq_config.py" && test -f "/var/www/securedrop/config.py"; then
password=$(head -c 32 /dev/urandom | base64)
echo "requirepass $password" | sudo -u redis tee -a /etc/redis/redis.conf
# Set in config.py for web apps
echo "REDIS_PASSWORD = \"$password\"" >> /var/www/securedrop/config.py
# Create separate rq_config for rqworker
touch /var/www/securedrop/rq_config.py
chown root:www-data /var/www/securedrop/rq_config.py
chmod 640 /var/www/securedrop/rq_config.py
echo "REDIS_PASSWORD = \"$password\"" > /var/www/securedrop/rq_config.py
service redis-server restart
fi
}

case "$1" in
configure)
Expand Down Expand Up @@ -235,12 +251,16 @@ case "$1" in
chown -R root:root /var/www/securedrop
chmod 755 /var/www/securedrop

# Make sure config.py is owned by root and readable by www-data,
# Make sure config.py and rq_config.py are owned by root and readable by www-data,
# but not world-readable
if [ -f "/var/www/securedrop/config.py" ]; then
chown root:www-data /var/www/securedrop/config.py
chmod 640 /var/www/securedrop/config.py
fi
if [ -f "/var/www/securedrop/rq_config.py" ]; then
chown root:www-data /var/www/securedrop/rq_config.py
chmod 640 /var/www/securedrop/rq_config.py
fi
# And logo needs to be writable by webserver user
# If there's no custom logo yet, copy the default in its place
if [ ! -f "/var/www/securedrop/static/i/custom_logo.png" ]; then
Expand Down Expand Up @@ -291,6 +311,9 @@ case "$1" in
# GPG -> Sequoia migration
export_journalist_public_key

# Set redis password
set_redis_password

# Version migrations
database_migration

Expand Down
Loading
Loading