View · Index

Weblog

Filtered by date 2026-01-30, 1 - 2 of 2 Postings (all, summary)

Enforcing POST for state-changing requests (require_post)

Created by Gustaf Neumann, last modified by Gustaf Neumann 06:54 PM, Friday

Motivation

State-changing operations (e.g., create/update/delete actions, membership or role management, administrative tasks) should not be reachable via HTTP GET requests.

GET requests are easy to trigger unintentionally or via social engineering (for example by clicking a link in an email). In modern browsers, session cookies with SameSite=Lax are still sent on cross-site top-level GET navigations, which makes such endpoints vulnerable to CSRF-style attacks if no additional protection is in place.

To reduce this attack surface, OpenACS applications can explicitly require HTTP POST for state-changing requests.

The ::template::require_post validator

 

The procedure ::template::require_post enforces that the current request uses the HTTP POST method. If the request is issued using any other method (typically GET), it returns a 405 Method Not Allowed response and aborts request processing.

This validator is intended to be used in the -validate blocks of ad_page_contract and ad_form.

Example A: Using require_post in ad_page_contract

 

ad_page_contract { 
    ... 
} -query { 
    email ... 
} -validate { 
    method { require_post } 
    csrf   { csrf::validate } 
} 
# Page implementation follows 

In this example:

  • require_post ensures that the request cannot be triggered via GET.

  • csrf::validate performs explicit CSRF token validation.

Placing the method check early in the validation phase ensures that invalid requests are rejected before any state-changing logic is executed.

Example B: Using require_post in ad_form

 

# If the data is not submitted via a POST request, bail out hard. 
# The request might originate from a forged or unintended request. 

ad_form \
    -name myform \
    -form { 
        {email:text {label "E-Mail"}} ... 
    } -validate {
        {email 
            { [require_post] } 
            "Only POST requests are allowed" 
        } 
    } -on_submit { 
        ... 
    } 

This pattern attaches the POST requirement directly to the form validation phase and ensures that the form submission cannot be triggered via a simple GET request.

Caveat: POST is not sufficient by itself

 

Requiring POST does not replace CSRF protection.

A determined attacker can still trigger cross-site POST requests (for example via auto-submitted forms). Proper CSRF protection therefore must include explicit CSRF token validation.

Requiring POST should be understood as a defense-in-depth measure:

  • It prevents accidental or link-based triggering of state-changing actions.

  • It improves the effectiveness of SameSite=Lax cookies.

  • It reduces the risk of subtle CSRF bugs caused by overlooked GET endpoints.

For full protection, state-changing endpoints should:

  1. Require POST

  2. Validate a CSRF token

  3. (Optionally) perform "Origin" or "Referer" checks for high-risk administrative actions

When to use this pattern

 

Use require_post for:

  • administrative pages (e.g., under /admin)

  • role or permission changes

  • membership management

  • any operation that modifies server-side state

Do not use require_post for:

  • read-only pages

  • bookmarkable navigation URLs

  • search, filtering, or pagination endpoints

See also

 

Security: Cross Site Request Forgery (CSRF)

Created by Gustaf Neumann, last modified by Gustaf Neumann 12:55 PM, Friday

Starting with OpenACS 5.9.1, OpenACS offers support for protecting against Cross Site Request Forgery (CSRF). In essence, this attack can cause a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated. The user gets a page presented, which looks harmless, but contains links or images that perform actions with the users credentials without the users consent. Note that the CSP does not protect a user against clicks on a malicious link.

CSRF protection works by ensuring that values for an action (e.g. by from a HTML form) are only accepted from a user that has received the form before. OpenACS generates by its security-procs a secure CSRF token value and provides it to a developer it in a global variable ::__csrf_token. When requests secured with the CSRF token are received, it can be validated on the server side. Note, that this mechanism is similar to "signing" values in OpenACS.

CSRF protection concerns of two parts: add the CSRF token to the form (POST requests) or to the href, and checking the received in the queries expecting input from CSRF protected resources. The first part works technically quite similar as securing CSP via nonces. Add code to the Tcl or ADP page that outputs the global variable (the test for the token is mostly for backwards compatibility)

    <form ...>
        ...
        <if @::__csrf_token@ defined>
           <input type="hidden" name="__csrf_token" value="@::__csrf_token;literal@">
        </if>
        ...
    </form>

Secondly, the page contract on the receiving side has to validate the csrf token. This can be achieved by adding a call to csrf::validate to the validation part of a page contract.

    ad_page_contract {
        @author ...
        @creation-date ...
    } -query {
       ...
    } -validate {
       ...
       csrf { csrf::validate }
    }

In the code base of OpenACS, CSRF protection was added on several places (e.g. public pages, the list template, etc.) such the checks of OpenACS sites on vulnerability scanners improve. Technically, it would be desirable to secure more places against CSRF attacks in the future. However, it depends on the requirements of a site whether e.g. the API browser or search should be CSRF protected. With protection turned on, one cannot share e.g. a link to a search with some other user (or a search engine). A site admin has to decide, how protected/public such links should be.

When using ad_formthe inclusion of the csrf token is done most conveniently via the  -csrf_protection_p flag:

    ad_form \
        ... \
        -csrf_protection_p true

previous January 2026
Sun Mon Tue Wed Thu Fri Sat
28 29 30 31 1 2 3
4 (1) 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 (2) 30 31

Popular tags

17 , 5.10 , 5.10.0 , 5.10.1 , 5.9.0 , 5.9.1 , ad_form , ADP , ajax , aolserver , asynchronous , Azure , bgdelivery , bootstrap , bugtracker , CentOS , COMET , compatibility , conference , CSP , CSRF , cvs , debian , docker , docker-compose , emacs , engineering-standards , exec , fedora , FreeBSD
No registered users in community xowiki
in last 30 minutes
Contributors

OpenACS.org