commit f81de57d9b83cf5705672b4dae247ce3eb44d183
parent 9048cd9bfb20a60910b4f8a2bde80dda51a42a98
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 6 Aug 2026 16:45:22 +0200
split curl context between reverse proxy and merchant to avoid leaking merchant authorization secret to target host
Diffstat:
5 files changed, 60 insertions(+), 20 deletions(-)
diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c
@@ -51,7 +51,9 @@ char *PH_merchant_base_url;
char *PH_base_url;
-struct GNUNET_CURL_Context *PH_ctx;
+struct GNUNET_CURL_Context *PH_merchant_ctx;
+
+struct GNUNET_CURL_Context *PH_proxy_ctx;
int PH_no_check;
@@ -80,9 +82,16 @@ const struct GNUNET_CONFIGURATION_Handle *PH_cfg;
/**
- * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
+ * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule() of
+ * #PH_merchant_ctx.
+ */
+static struct GNUNET_CURL_RescheduleContext *merchant_ctx_rc;
+
+/**
+ * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule() of
+ * #PH_proxy_ctx.
*/
-static struct GNUNET_CURL_RescheduleContext *ctx_rc;
+static struct GNUNET_CURL_RescheduleContext *proxy_ctx_rc;
/* *************** General / main code *************** */
@@ -193,15 +202,25 @@ do_shutdown (void *cls)
regfree (&PH_whitelist_ex);
PH_have_whitelist_ex = false;
}
- if (NULL != PH_ctx)
+ if (NULL != PH_merchant_ctx)
+ {
+ GNUNET_CURL_fini (PH_merchant_ctx);
+ PH_merchant_ctx = NULL;
+ }
+ if (NULL != merchant_ctx_rc)
+ {
+ GNUNET_CURL_gnunet_rc_destroy (merchant_ctx_rc);
+ merchant_ctx_rc = NULL;
+ }
+ if (NULL != PH_proxy_ctx)
{
- GNUNET_CURL_fini (PH_ctx);
- PH_ctx = NULL;
+ GNUNET_CURL_fini (PH_proxy_ctx);
+ PH_proxy_ctx = NULL;
}
- if (NULL != ctx_rc)
+ if (NULL != proxy_ctx_rc)
{
- GNUNET_CURL_gnunet_rc_destroy (ctx_rc);
- ctx_rc = NULL;
+ GNUNET_CURL_gnunet_rc_destroy (proxy_ctx_rc);
+ proxy_ctx_rc = NULL;
}
}
@@ -494,9 +513,10 @@ run (void *cls,
&paivana_secret);
GNUNET_free (secret);
}
- PH_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &ctx_rc);
- GNUNET_assert (NULL != PH_ctx);
+ PH_proxy_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &proxy_ctx_rc);
+ GNUNET_assert (NULL != PH_proxy_ctx);
+ proxy_ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_proxy_ctx);
if (! PH_no_check)
{
char *merchant_access_token;
@@ -516,17 +536,25 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ /* A second context, because the credential below is appended to
+ *every* request the context makes: on a shared context we would
+ hand our merchant bearer token to the origin server (and to
+ whoever it redirects to) on each forwarded request. */
+ PH_merchant_ctx
+ = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &merchant_ctx_rc);
+ GNUNET_assert (NULL != PH_merchant_ctx);
+ merchant_ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_merchant_ctx);
GNUNET_asprintf (&auth_header,
"%s: Bearer %s",
MHD_HTTP_HEADER_AUTHORIZATION,
merchant_access_token);
GNUNET_free (merchant_access_token);
GNUNET_assert (GNUNET_OK ==
- GNUNET_CURL_append_header (PH_ctx,
+ GNUNET_CURL_append_header (PH_merchant_ctx,
auth_header));
GNUNET_free (auth_header);
}
- ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_ctx);
/* Once templates are done loading, this will
start the daemon as well. In -n (no-payment) mode we skip
the merchant round-trip entirely. */
diff --git a/src/backend/paivana-httpd.h b/src/backend/paivana-httpd.h
@@ -90,9 +90,21 @@ extern char *PH_merchant_base_url;
extern char *PH_base_url;
/**
- * Curl context for making HTTP requests.
+ * Curl context for talking to the merchant backend. Carries the
+ * `Authorization: Bearer $MERCHANT_ACCESS_TOKEN` header on every
+ * request, so it must never be used for anything but the backend.
+ * NULL in `-n` (no payment) mode, where there is no backend.
*/
-extern struct GNUNET_CURL_Context *PH_ctx;
+extern struct GNUNET_CURL_Context *PH_merchant_ctx;
+
+/**
+ * Curl context for forwarding client requests to the origin server.
+ * Deliberately separate from #PH_merchant_ctx: headers appended to a
+ * context apply to every request made through it, and our credentials
+ * for the merchant backend have no business being sent to the site we
+ * proxy for.
+ */
+extern struct GNUNET_CURL_Context *PH_proxy_ctx;
/**
* Pre-compiled regular expression for sites that are whitelisted
diff --git a/src/backend/paivana-httpd_pay.c b/src/backend/paivana-httpd_pay.c
@@ -479,7 +479,7 @@ PAIVANA_HTTPD_payment_handle (struct PayRequest *ph,
}
}
GNUNET_assert (NULL == ph->co);
- ph->co = TALER_MERCHANT_get_private_order_create (PH_ctx,
+ ph->co = TALER_MERCHANT_get_private_order_create (PH_merchant_ctx,
PH_merchant_base_url,
ph->order_id);
if (NULL == ph->co)
diff --git a/src/backend/paivana-httpd_reverse.c b/src/backend/paivana-httpd_reverse.c
@@ -1930,7 +1930,7 @@ start_curl_request (struct HttpRequest *hr,
append_forwarded_headers (hr,
con,
ver);
- hr->job = GNUNET_CURL_job_add_raw (PH_ctx,
+ hr->job = GNUNET_CURL_job_add_raw (PH_proxy_ctx,
hr->curl,
hr->headers,
&curl_download_cb,
diff --git a/src/backend/paivana-httpd_templates.c b/src/backend/paivana-httpd_templates.c
@@ -618,7 +618,7 @@ check_templates (
t = GNUNET_new (struct Template);
t->template_id = GNUNET_strdup (te->template_id);
t->max_pickup_delay = GNUNET_TIME_UNIT_FOREVER_REL;
- t->gt = TALER_MERCHANT_get_private_template_create (PH_ctx,
+ t->gt = TALER_MERCHANT_get_private_template_create (PH_merchant_ctx,
PH_merchant_base_url,
t->template_id);
GNUNET_CONTAINER_DLL_insert (t_head,
@@ -636,7 +636,7 @@ check_templates (
void
PAIVANA_HTTPD_load_templates ()
{
- gpt = TALER_MERCHANT_get_private_templates_create (PH_ctx,
+ gpt = TALER_MERCHANT_get_private_templates_create (PH_merchant_ctx,
PH_merchant_base_url);
GNUNET_assert (NULL != gpt);
GNUNET_assert (