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

feat: enable Tor's proof-of-work defense on the Source Interface #7175

Merged
merged 5 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
12 changes: 11 additions & 1 deletion admin/securedrop_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,21 @@ def __init__(self, args: argparse.Namespace) -> None:
None,
lambda config: True,
),
(
"securedrop_app_pow_on_source_interface",
True,
bool,
"Enable Tor's proof-of-work defense against denial-of-service attacks for the "
"Source Interface?",
SiteConfig.ValidateYesNo(),
lambda x: x.lower() == "yes",
lambda config: True,
),
cfm marked this conversation as resolved.
Show resolved Hide resolved
(
"securedrop_app_https_on_source_interface",
False,
bool,
"Whether HTTPS should be enabled on " + "Source Interface (requires EV cert)",
"Enable HTTPS for the Source Interface (requires EV certificate)?",
SiteConfig.ValidateYesNo(),
lambda x: x.lower() == "yes",
lambda config: True,
Expand Down
31 changes: 26 additions & 5 deletions admin/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
securedrop_app_https_certificate_chain_src: ''
securedrop_app_https_certificate_key_src: ''
securedrop_app_https_on_source_interface: false
securedrop_app_pow_on_source_interface: true
securedrop_supported_locales:
- de_DE
- es_ES
Expand Down Expand Up @@ -73,6 +74,7 @@
securedrop_app_https_certificate_chain_src: ''
securedrop_app_https_certificate_key_src: ''
securedrop_app_https_on_source_interface: false
securedrop_app_pow_on_source_interface: true
securedrop_supported_locales:
- de_DE
- es_ES
Expand All @@ -81,7 +83,7 @@
ssh_users: sd
"""

HTTPS_OUTPUT = """app_hostname: app
HTTPS_OUTPUT_NO_POW = """app_hostname: app
app_ip: 10.20.2.2
daily_reboot_time: 5
dns_server:
Expand All @@ -105,6 +107,7 @@
securedrop_app_https_certificate_chain_src: ca.crt
securedrop_app_https_certificate_key_src: key.asc
securedrop_app_https_on_source_interface: true
securedrop_app_pow_on_source_interface: false
securedrop_supported_locales:
- de_DE
- es_ES
Expand Down Expand Up @@ -188,9 +191,16 @@ def verify_app_gpg_key_prompt(child):
)


def verify_tor_pow_prompt(child):
# We don't need child.expect()'s regex matching, but the prompt is too long
# to match on the whole thing.
child.expect_exact("Enable Tor's proof-of-work defense", timeout=2)


def verify_https_prompt(child):
child.expect(
rb"Whether HTTPS should be enabled on Source Interface \(requires EV cert\)\:", timeout=2
# We don't need child.expect()'s regex matching.
child.expect_exact(
"Enable HTTPS for the Source Interface (requires EV certificate)?:", timeout=2
)


Expand Down Expand Up @@ -312,6 +322,9 @@ def test_sdconfig_on_first_run():
child.sendline("")
verify_app_gpg_key_prompt(child)
child.sendline("\b" * 14 + "sd_admin_test.pub")
verify_tor_pow_prompt(child)
# Default answer is yes
child.sendline("")
verify_https_prompt(child)
# Default answer is no
child.sendline("")
Expand Down Expand Up @@ -375,7 +388,11 @@ def test_sdconfig_enable_journalist_alerts():
child.sendline("")
verify_app_gpg_key_prompt(child)
child.sendline("\b" * 14 + "sd_admin_test.pub")
verify_tor_pow_prompt(child)
# Default answer is yes
child.sendline("")
verify_https_prompt(child)
child.sendline("")
# Default answer is no
child.sendline("")
verify_app_gpg_fingerprint_prompt(child)
Expand Down Expand Up @@ -422,7 +439,7 @@ def test_sdconfig_enable_journalist_alerts():
verify_install_has_valid_config()


def test_sdconfig_enable_https_on_source_interface():
def test_sdconfig_enable_https_disable_pow_on_source_interface():
cmd = os.path.join(os.path.dirname(CURRENT_DIR), "securedrop_admin/__init__.py")
child = pexpect.spawn(f"python {cmd} --force --root {SD_DIR} sdconfig")
verify_username_prompt(child)
Expand All @@ -441,6 +458,10 @@ def test_sdconfig_enable_https_on_source_interface():
child.sendline("")
verify_app_gpg_key_prompt(child)
child.sendline("\b" * 14 + "sd_admin_test.pub")
verify_tor_pow_prompt(child)
# Default answer is yes
# We will press backspace thrice and type no
child.sendline("\b\b\bno")
verify_https_prompt(child)
# Default answer is no
# We will press backspace twice and type yes
Expand Down Expand Up @@ -490,7 +511,7 @@ def test_sdconfig_enable_https_on_source_interface():
os.path.join(SD_DIR, "install_files/ansible-base/group_vars/all/site-specific")
) as fobj:
data = fobj.read()
assert data == HTTPS_OUTPUT
assert data == HTTPS_OUTPUT_NO_POW

verify_install_has_valid_config()

Expand Down
1 change: 1 addition & 0 deletions admin/tests/test_securedrop-admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ def auto_prompt(prompt, default, **kwargs):
verify_prompt_monitor_hostname = verify_desc_consistency
verify_prompt_dns_server = verify_desc_consistency

verify_prompt_securedrop_app_pow_on_source_interface = verify_prompt_boolean
verify_prompt_securedrop_app_https_on_source_interface = verify_prompt_boolean
verify_prompt_enable_ssh_over_tor = verify_prompt_boolean

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ RunAsDaemon 1
HiddenServiceDir /var/lib/tor/services/sourcev3
HiddenServicePort 80 127.0.0.1:80

{% if securedrop_app_pow_on_source_interface|default(True) %}
cfm marked this conversation as resolved.
Show resolved Hide resolved
HiddenServicePoWDefensesEnabled 1
cfm marked this conversation as resolved.
Show resolved Hide resolved
{% endif %}

{% if securedrop_app_https_on_source_interface|default(False) %}
HiddenServicePort 443 127.0.0.1:443
{% endif %}
Expand Down