Cross Site Request Forgery (CSRF)¶
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
evil.example.comsite emits some kind of hyperlink (
<SCRIPT>, etc) which tells the browser to send a request to
- 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.
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
- Authenticate with a mechanism that is not susceptible to CSRF.
The rationales for each are examined below.
When does APIv3/APIv4 require
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 (
X-Requested-With:is not required for bespoke authentication mechanisms (
- Before v5.47, CSRF protection depends on the end-point URL:
X-Requested-With:is required by
civicrm/ajax/*-- regardless of whether you use standard or bespoke authentication.
X-Requested-With:is not required by
extern/rest.php. This is not required because
extern/rest.phponly supports bespoke authentication (
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 (
<FORM ACTION>, etc), but none of them can specify the
https://crm.example.org can send custom-headers to
What authentication mechanisms are susceptible to CSRF?¶
CSRF attacks exploit standard HTTP headers such as
Authorization:. For example, when a user logs into
crm.example.org, the browser makes a note to continue sending
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
The browser does not send
?api_key= automatically -- so it's not a vector for CSRF.
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 (
Authorization:) but not for
bespoke authentication flows (
TODO: Discuss qfid mechanism