You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by as...@apache.org on 2026/04/21 19:02:12 UTC

(tooling-agents) branch main updated: ASVS L3 audit: 12.1.1 (tls_and_transport_security)

This is an automated email from the ASF dual-hosted git repository.

asf-tooling pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new 4ed4a45  ASVS L3 audit: 12.1.1 (tls_and_transport_security)
4ed4a45 is described below

commit 4ed4a45cb0b86ab05e5bdc00c031117f82536de1
Author: ASF Tooling Team <ro...@apache.org>
AuthorDate: Tue Apr 21 21:02:08 2026 +0200

    ASVS L3 audit: 12.1.1 (tls_and_transport_security)
---
 .../d0aa7e9/tls_and_transport_security/12.1.1.md   | 254 +++++++++++++++++++++
 1 file changed, 254 insertions(+)

diff --git a/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.1.1.md b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.1.1.md
new file mode 100644
index 0000000..ff9d3f6
--- /dev/null
+++ b/repos/apache/ASVS/reports/steve/v3/d0aa7e9/tls_and_transport_security/12.1.1.md
@@ -0,0 +1,254 @@
+# ASVS 12.1.1 Security Audit Report
+
+## Executive Summary
+
+- **Repository:** apache/steve
+- **Audit Date:** Apr 21, 2026
+- **Auditor:** Tooling Agents
+- **ASVS Requirement:** 12.1.1 — Verify that only the latest recommended versions of the TLS protocol are enabled, such as TLS 1.2 and TLS 1.3. The latest version of the TLS protocol must be the preferred option.
+  - **Level:** 1
+  - **Section:** General TLS Security Guidance
+  - **Chapter:** Secure Communication
+- **Files Analyzed:** 2 relevant out of 2 total, 0 skipped
+
+### Finding Summary
+
+| Severity | Count |
+|----------|-------|
+| Critical | 0 |
+| High | 0 |
+| Medium | 0 |
+| Low | 0 |
+
+**Audit Conclusion:** The audit of the Quart-based voting server's TLS configuration against ASVS 12.1.1 reveals a **critical gap**: the application provides no explicit TLS protocol version enforcement. When TLS is enabled via certificate configuration, the server passes raw `certfile`/`keyfile` paths to the underlying framework without constructing or configuring an `ssl.SSLContext`, leaving protocol version negotiation entirely to system-level OpenSSL defaults.
+
+---
+
+## Security Controls Inventory
+
+| Control Area | Expected | Found | Status |
+|--------------|----------|-------|--------|
+| TLS certificate configuration | Present | `config.yaml` certfile/keyfile | ✅ Exists |
+| TLS protocol minimum version (≥1.2) | Explicit enforcement | **None** | ❌ Missing |
+| TLS 1.3 preferred | Explicit preference | **None** | ❌ Missing |
+| Deprecated protocol disable (TLS 1.0, 1.1) | Explicit disable | **None** | ❌ Missing |
+| SSL context creation | Custom `ssl.SSLContext` | **None** | ❌ Missing |
+| Cipher suite restriction | Explicit configuration | **None** | ❌ Missing |
+
+---
+
+## Critical File Review
+
+### TLS Configuration Analysis
+
+| File | TLS Controls | Protocol Version Config | Cipher Config | Verdict |
+|------|--------------|------------------------|---------------|---------|
+| `main.py` | Certificate paths loaded conditionally | **None** | **None** | ❌ Non-compliant |
+| `config.yaml.example` | certfile/keyfile fields | **No protocol fields** | **No cipher fields** | ❌ Incomplete |
+
+---
+
+## Findings
+
+### Critical Severity
+
+#### ASVS-1211-SEV-001: No TLS Protocol Version Enforcement — Server May Accept Deprecated TLS 1.0/1.1 Connections
+
+**Severity:** CRITICAL
+
+**Gap Type:** Type A — Entry point with NO control
+
+**Location:** 
+- **File:** `v3/server/main.py`
+- **Function:** `run_standalone()`
+- **Lines:** 83–91
+
+**Related Functions Checked:**
+- `run_standalone()` (lines 83–91)
+- `run_asgi()` (lines 99–118)
+
+**Vulnerable Code:**
+
+```python
+kwargs = {}
+if app.cfg.server.certfile:
+    kwargs['certfile'] = CERTS_DIR / app.cfg.server.certfile
+    kwargs['keyfile'] = CERTS_DIR / app.cfg.server.keyfile
+    extra_files.update((kwargs['certfile'], kwargs['keyfile']))
+
+# Spool up the app!
+app.runx(port=app.cfg.server.port, extra_files=extra_files, **kwargs)
+```
+
+**Configuration (config.yaml.example):**
+```yaml
+server:
+    certfile: localhost.apache.org+3.pem
+    keyfile: localhost.apache.org+3-key.pem
+```
+
+**Data Flow:**
+
+```
+config.yaml (certfile/keyfile paths)
+  → main.py:run_standalone() constructs kwargs with raw paths
+    → app.runx(**kwargs) passes paths to Hypercorn/Quart
+      → Framework creates ssl.SSLContext with SYSTEM DEFAULTS
+        → No minimum_version set → TLS 1.0/1.1 potentially negotiable
+```
+
+**Analysis:**
+
+The application constructs TLS parameters by passing only `certfile` and `keyfile` as keyword arguments to `app.runx()`. At no point in the codebase is an `ssl.SSLContext` explicitly created or configured. This means:
+
+1. **No `ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2`** — Python's `ssl.SSLContext` defaults `minimum_version` to `TLSVersion.MINIMUM_SUPPORTED`, which is typically TLS 1.0 on most systems.
+2. **No protocol flags** — No use of `ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1` to disable deprecated versions.
+3. **No TLS 1.3 preference** — No configuration ensures TLS 1.3 is the preferred negotiation outcome.
+4. **Both deployment modes affected** — `run_standalone()` passes raw paths; `run_asgi()` creates no SSL configuration at all, deferring entirely to Hypercorn's own defaults (which are also system-dependent without explicit config).
+
+For ASGI mode specifically (`run_asgi()` at lines 99–118), there is no Hypercorn configuration file or programmatic SSL context setup in the codebase at all, meaning TLS configuration for production ASGI deployment is completely uncontrolled by the application.
+
+**Proof of Concept:**
+
+An attacker can force a protocol downgrade using a client that only advertises TLS 1.0:
+
+```bash
+# Attempt TLS 1.0 connection against the voting server
+openssl s_client -connect voting-server:58383 -tls1
+
+# Attempt TLS 1.1 connection
+openssl s_client -connect voting-server:58383 -tls1_1
+
+# If either succeeds, the server accepts deprecated protocols
+# An on-path attacker can then exploit known TLS 1.0/1.1 weaknesses
+# (BEAST, POODLE padding oracle, Lucky Thirteen) to decrypt
+# authentication tokens or encrypted vote payloads in transit
+```
+
+**Impact:**
+
+- **Confidentiality:** Authentication tokens (OAuth session cookies) and vote submissions transmitted over deprecated TLS versions are vulnerable to known cryptographic attacks (BEAST on TLS 1.0 CBC ciphers, Lucky Thirteen timing attacks on TLS 1.0/1.1).
+- **Integrity:** A man-in-the-middle attacker exploiting TLS 1.0/1.1 weaknesses could modify vote payloads or inject election management API calls.
+- **Compliance:** Direct violation of ASVS 12.1.1 Level 1 which requires that "only the latest recommended versions of the TLS protocol are enabled, such as TLS 1.2 and TLS 1.3."
+- **Context:** This is a voting system where the domain context explicitly identifies "strong transport security is critical to prevent man-in-the-middle attacks and session hijacking."
+
+**Remediation:**
+
+Create an explicit `ssl.SSLContext` with enforced minimum version and pass it to the server framework:
+
+```python
+import ssl
+
+def _create_tls_context(certfile: pathlib.Path, keyfile: pathlib.Path) -> ssl.SSLContext:
+    """Create a hardened TLS context enforcing TLS 1.2+ with TLS 1.3 preferred."""
+    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+    
+    # Enforce TLS 1.2 as minimum, TLS 1.3 as maximum/preferred
+    ctx.minimum_version = ssl.TLSVersion.TLSv1_2
+    ctx.maximum_version = ssl.TLSVersion.TLSv1_3
+    
+    # Disable compression (CRIME attack) and enforce server cipher order
+    ctx.options |= (
+        ssl.OP_NO_COMPRESSION
+        | ssl.OP_CIPHER_SERVER_PREFERENCE
+        | ssl.OP_SINGLE_DH_USE
+        | ssl.OP_SINGLE_ECDH_USE
+    )
+    
+    # Restrict cipher suites to strong modern ciphers
+    ctx.set_ciphers(
+        'ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20'
+        ':!aNULL:!MD5:!DSS:!RC4:!3DES'
+    )
+    
+    ctx.load_cert_chain(certfile=str(certfile), keyfile=str(keyfile))
+    return ctx
+
+
+def run_standalone():
+    # ... existing setup ...
+    
+    app = create_app()
+    
+    kwargs = {}
+    if app.cfg.server.certfile:
+        certfile = CERTS_DIR / app.cfg.server.certfile
+        keyfile = CERTS_DIR / app.cfg.server.keyfile
+        
+        # Create hardened SSL context instead of passing raw paths
+        ssl_context = _create_tls_context(certfile, keyfile)
+        kwargs['ssl'] = ssl_context
+        
+        extra_files.update((certfile, keyfile))
+    
+    app.runx(port=app.cfg.server.port, extra_files=extra_files, **kwargs)
+```
+
+For ASGI/Hypercorn deployment, provide a `hypercorn.toml` configuration:
+
+```toml
+# hypercorn.toml
+certfile = "certs/server.pem"
+keyfile = "certs/server-key.pem"
+
+# Enforce TLS 1.2+ with modern ciphers
+ciphers = "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS"
+```
+
+---
+
+## Positive Security Patterns
+
+| Pattern | Location | Assessment |
+|---------|----------|------------|
+| TLS support is available | `config.yaml`, `main.py` lines 83-87 | Certificate-based TLS is supported, just not hardened |
+| `pathlib` used for path construction | `main.py` line 32, 87-88 | Safe path handling prevents path traversal in cert loading |
+| OAuth over HTTPS | `main.py` lines 42-45 | OAuth endpoints correctly use `https://` scheme |
+| Static folder disabled | `main.py` line 49 | `static_folder=None` reduces attack surface |
+| Certificate file watching | `main.py` lines 88-89 | Supports certificate rotation without manual restart |
+
+---
+
+## Architecture Observations
+
+1. **Dual deployment modes create divergent TLS postures:** The standalone mode (`run_standalone`) at least passes cert/key to the framework. The ASGI mode (`run_asgi`) provides zero TLS configuration, fully delegating to external Hypercorn configuration that is not part of this codebase and may not exist.
+
+2. **Optional TLS is a deployment risk:** The config comment "leave these two fields blank for plain HTTP" means production deployments could accidentally run without TLS. While the comment notes "a proxy sits in front of this server," there is no programmatic check or warning when TLS is disabled.
+
+3. **No TLS configuration schema:** The `config.yaml` schema only supports `certfile` and `keyfile`. There are no fields for `minimum_tls_version`, `ciphers`, or `ssl_context` options, meaning even a security-conscious operator cannot enforce protocol versions through configuration alone.
+
+---
+
+## Recommendations Summary
+
+### Immediate Priority
+
+| Priority | Action | Effort |
+|----------|--------|--------|
+| **1** | Create an explicit `ssl.SSLContext` in `run_standalone()` with `minimum_version = TLSv1_2` and strong cipher suites | Low |
+| **2** | Add `minimum_tls_version` and `ciphers` fields to the config schema so operators can control TLS settings | Low |
+
+### Short-term Priority
+
+| Priority | Action | Effort |
+|----------|--------|--------|
+| **3** | Provide a hardened `hypercorn.toml` template for ASGI deployments that enforces TLS 1.2+ and modern ciphers | Low |
+| **4** | Add a startup warning/abort when `certfile` is empty and the server is not binding to localhost, to prevent accidental plain-HTTP production deployments | Low |
+
+### Long-term Priority
+
+| Priority | Action | Effort |
+|----------|--------|--------|
+| **5** | Integrate automated TLS configuration scanning (e.g., `testssl.sh` or `sslyze`) into CI/CD to verify protocol compliance on each release | Medium |
+
+---
+
+## Appendix: Files Analyzed
+
+<details>
+<summary>Click to expand file list (2 files)</summary>
+
+1. `v3/server/config.yaml.example` (relevance: 10)
+2. `v3/server/main.py` (relevance: 10)
+
+</details>
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org