From 7fabccd90a977462572df3335ced004a7138e601 Mon Sep 17 00:00:00 2001 From: udo Date: Mon, 13 Jul 2026 23:52:49 +0000 Subject: [PATCH] Add CSRF hidden field helper --- site/doc/pages/csrf_field.txt | 27 +++++++++++++++++++++++++++ site/doc/pages/csrf_token.txt | 1 + site/tests/http.uce | 8 ++++++++ src/lib/uri.cpp | 7 +++++++ src/lib/uri.h | 1 + 5 files changed, 44 insertions(+) create mode 100644 site/doc/pages/csrf_field.txt diff --git a/site/doc/pages/csrf_field.txt b/site/doc/pages/csrf_field.txt new file mode 100644 index 0000000..1177a29 --- /dev/null +++ b/site/doc/pages/csrf_field.txt @@ -0,0 +1,27 @@ +:sig +String csrf_field(String session_name = "uce-session", String token_name = "csrf_token", String field_name = "") + +:params +session_name : session/cookie name to store the token under +token_name : form/action token namespace +field_name : submitted POST field name; defaults to `token_name` +return value : HTML hidden input containing the active CSRF token + +:content +Starts the named session if needed and returns the standard hidden form input for a CSRF token. The field name and generated token value are HTML-escaped. + +Use this in ordinary server-rendered POST forms when the submitted field name should match `token_name`, or pass `field_name` when several forms share the same submitted parameter name but need separate token namespaces. Validate the submitted value with `csrf_valid(context.post[field_name], session_name, token_name)` before mutating state. + +:example +?>
+ + + +
http +csrf_token +csrf_valid +csrf_rotate +session_start diff --git a/site/doc/pages/csrf_token.txt b/site/doc/pages/csrf_token.txt index f47a1da..75506a7 100644 --- a/site/doc/pages/csrf_token.txt +++ b/site/doc/pages/csrf_token.txt @@ -21,6 +21,7 @@ String token = csrf_token("uce-doc-session"); :see >http csrf_valid +csrf_field csrf_rotate session_start random_bytes diff --git a/site/tests/http.uce b/site/tests/http.uce index bc23d52..30d46f6 100644 --- a/site/tests/http.uce +++ b/site/tests/http.uce @@ -37,6 +37,8 @@ RENDER(Request& context) URI port_uri = parse_uri("https://example.test:8443/status"); String generated_session = session_id_create(); String csrf = ""; + String csrf_html = ""; + String csrf_named_html = ""; String csrf_rotated = ""; bool csrf_ok = false; bool csrf_bad = false; @@ -45,6 +47,8 @@ RENDER(Request& context) if(action != "destroy") { csrf = csrf_token("uce-site-tests", "http_form"); + csrf_html = csrf_field("uce-site-tests", "http_form"); + csrf_named_html = csrf_field("uce-site-tests", "http_form", "csrf_token"); csrf_ok = csrf_valid(csrf, "uce-site-tests", "http_form"); csrf_bad = csrf_valid("not-" + csrf, "uce-site-tests", "http_form"); csrf_rotate("uce-site-tests", "http_form"); @@ -76,7 +80,11 @@ RENDER(Request& context) check("session_start()", session_id != "", "session_id=" + session_id); check("session_id_create()", generated_session.length() >= 16, generated_session); if(action != "destroy") + { check("csrf_token() / csrf_valid() / csrf_rotate()", csrf.length() >= 32 && csrf_ok && !csrf_bad && !csrf_old_after_rotate && csrf_new_after_rotate, "csrf=" + csrf + " rotated=" + csrf_rotated); + check("csrf_field()", csrf_html == "", csrf_html); + check("csrf_field() custom field name", csrf_named_html == "", csrf_named_html); + } if(action == "destroy") check("session_destroy()", session_dump.find("suite") == String::npos && context.session_id == "" && context.session_name == "" && !file_exists(session_path), session_dump + " path=" + session_path); diff --git a/src/lib/uri.cpp b/src/lib/uri.cpp index f22aeb7..ce342cf 100644 --- a/src/lib/uri.cpp +++ b/src/lib/uri.cpp @@ -885,6 +885,13 @@ String csrf_token(String session_name, String token_name) return(context->session[key]); } +String csrf_field(String session_name, String token_name, String field_name) +{ + token_name = first(trim(token_name), "csrf_token"); + field_name = first(trim(field_name), token_name); + return(""); +} + bool csrf_valid(String submitted_token, String session_name, String token_name) { session_start(session_name); diff --git a/src/lib/uri.h b/src/lib/uri.h index 904584f..73b3249 100644 --- a/src/lib/uri.h +++ b/src/lib/uri.h @@ -34,6 +34,7 @@ void save_session_data(String session_id, StringMap data); String session_start(String session_name = "uce-session"); void session_destroy(String session_name = "uce-session"); String csrf_token(String session_name = "uce-session", String token_name = "csrf_token"); +String csrf_field(String session_name = "uce-session", String token_name = "csrf_token", String field_name = ""); bool csrf_valid(String submitted_token, String session_name = "uce-session", String token_name = "csrf_token"); void csrf_rotate(String session_name = "uce-session", String token_name = "csrf_token"); String ws_make_accept_key(String client_key);