Cross Site Request Forgery (CSRF)¶
General¶
What is CSRF?¶
Cross-site request forgery (CSRF) is a type of browser-based attack involving a user who visits two sites:
- A web-based user logs into one site (eg
https://crm.example.org). They have an active browser session/cookie on this site. - Later, the same user casually browses to another site (eg
https://evil.example.com). - The
evil.example.comsite emits some kind of hyperlink (<A HREF>,<FORM ACTION>,<IFRAME>,<IMG>,<SCRIPT>, etc) which tells the browser to send a request tocrm.example.org, eg<img src="https://crm.example.org/civicrm/ajax/rest?entity=Contact&action=delete&..."/> - The browser requests this hyperlink. Because the user has an active session and suitable permission,
crm.example.orgperforms the requested action (eg deleting random contacts). - Of course, the user didn't actually want to delete anything. This was a surreptitious request sent on their behalf.
How does CiviCRM protect against CSRF?¶
There are different techniques - some techniques are used for REST services (eg APIv3/APIv4); other techniques are used for web forms (such as HTML_QuickForm).
When should CSRF protections be required?¶
Requests which actively manipulate data must have CSRF protection. For example, civicrm/ajax/rest must have CSRF protection.
Requests which passively display linkable screens must not have CSRF protection. For example, civicrm/event/info must not have CSRF protection.
Many workflows involve a hybrid. For example, it is useful to have external hyperlinks to civicrm/event/register. The first page-load
presents a form to a user; this page does not require CSRF protection. As the user interacts with the form (eg using rich widgets that require
APIs; eg submitting the form to finish regstration), the page sends additional requests - and these do require CSRF protection.
APIv3/APIv4 REST¶
All requests for APIv3 REST and APIv4 REST are assessed for CSRF risk - they must have some attribute to indicate that CSRF is not a concern. Either:
- Send the header
X-Requested-With: XMLHttpRequest. - Authenticate with a mechanism that is not susceptible to CSRF.
The rationales for each are examined below.
When does APIv3/APIv4 require X-Requested-With?¶
It varies by version, authentication mechanism, and/or end-point. For APIv3/APIv4:
- After v5.47+, CSRF protection depends on the authentication mechanism:
X-Requested-With:is required if you authenticate with standard HTTP headers (Cookie:orAuthorization:).X-Requested-With:is not required for bespoke authentication mechanisms (X-Civi-Auth:,?_authx=,?api_key=).
- Before v5.47, CSRF protection depends on the end-point URL:
X-Requested-With:is required bycivicrm/ajax/*-- regardless of whether you use standard or bespoke authentication.X-Requested-With:is not required byextern/rest.php. This is not required becauseextern/rest.phponly supports bespoke authentication (?api_key).
How does X-Requested-With mitigate CSRF?¶
When the browser follows a regular HTML hyperlink, it only sends standard headers. X-Requested-With: is a custom-header.
evil.example.com can generate HTML hyperlinks in many ways (<A HREF>, <FORM ACTION>, etc), but none of them can specify the
custom-header X-Requested-With:.
Browsers will send custom-headers under some other circumstances; notably, Javascript logic can send a custom-header. However, this is
subject to the standard Same Origin Policy. Javascript on https://crm.example.org can send custom-headers to crm.example.org; but
Javascript on https://evil.example.com cannot.
What authentication mechanisms are susceptible to CSRF?¶
CSRF attacks exploit standard HTTP headers such as Cookie: and/or Authorization:. For example, when a user logs into
crm.example.org, the browser makes a note to continue sending Cookie: and/or Authorization: with every subsequent request (regardless
of how the request is initiated). This automatic behavior creates the opportunity for CSRF.
For contrast, consider the legacy end-point extern/rest.php. Instead of standard headers, it uses the bespoke parameter ?api_key=.
The browser does not send ?api_key= automatically -- so it's not a vector for CSRF.
Hypothetically, evil.example.com could construct a hyperlink to extern/rest.php?api_key=MY_API_KEY. But they need to specify
MY_API_KEY. If they don't specify MY_API_KEY, then the request is anonymous - and conveys no extra privileges. If they do specify
MY_API_KEY, then you have a prior security compromise. CSRF countermeasures like X-Requested-With: won't protect you from an attacker
who already has an API key.
In short, CSRF is an important consideration for standard browser-based authentication flows (Cookie:/Authorization:) but not for
bespoke authentication flows (?api_key=, X-Civi-Auth:).
QuickForm¶
TODO: Discuss qfid mechanism