paivana

HTTP paywall reverse proxy
Log | Files | Refs | Submodules | README | LICENSE

commit ccd0fb34b4f024eb9651fc9ee26104a67d33e5b0
parent fbf6112d5c4c87ea61ca05c10299c860317de406
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  6 Aug 2026 16:07:39 +0200

fix base_url check: handle NULL, enforce '/' termination

Diffstat:
Msrc/backend/paivana-httpd_pay.c | 47++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/src/backend/paivana-httpd_pay.c b/src/backend/paivana-httpd_pay.c @@ -163,6 +163,49 @@ PAIVANA_HTTPD_payment_create (struct MHD_Connection *connection) /** + * Is @a website a URL below our own base URL? + * + * Used to bound where a client may send itself once it has paid for + * an order that carries no fulfillment URL of its own: without this + * the client picks the redirect target and the site the access cookie + * is minted for. + * + * The comparison is on whole path segments. A bare prefix test would + * accept "https://example.com.evil.net/" for a base URL of + * "https://example.com", because strip_trailing_slashes() has removed + * the '/' that used to terminate it. + * + * @param website candidate URL, from the client + * @return true if @a website is our base URL or something below it + */ +static bool +under_our_base_url (const char *website) +{ + size_t blen; + + if (NULL == PH_base_url) + { + /* BASE_URL is optional; without it we have nothing to compare + against and must not guess. Note that dereferencing it here + used to be an unconditional crash. */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Cannot check the target of an order without a" + " fulfillment URL: BASE_URL is not configured\n"); + return false; + } + blen = strlen (PH_base_url); + if (0 != strncmp (website, + PH_base_url, + blen)) + return false; + /* PH_base_url has no trailing '/' (strip_trailing_slashes()), so + require the boundary here rather than inheriting it. */ + return ('\0' == website[blen]) || + ('/' == website[blen]); +} + + +/** * Check that the @a contract that was paid is reasonable for the * request in @a ph, that is that we would indeed consider this * contract to apply for the website and duration indicated @@ -221,9 +264,7 @@ check_contract (struct PayRequest *ph, return false; } if ( ( (NULL == target) && - (0 != strncmp (ph->website, - PH_base_url, - strlen (PH_base_url))) ) || + (! under_our_base_url (ph->website)) ) || (! TALER_is_web_url (ph->website)) ) { /* Bad: the order has no fulfillment URL, and on top of that