Newer Version Available

This content describes an older version of this product. View Latest

Protect Your Application from CSRF Vulnerabilities

Secure your applications against CSRF vulnerabilities. While Salesforce automatically protects components built with Apex and Visualforce, verify that protections are enabled when using other development frameworks.

CSRF Considerations and Limitations

Salesforce automatically protects most form-based requests from CSRF. Standard controllers and methods secure actions such as, insert, update, delete, and upsert when triggered by user interactions. These interactions include clicking a button or submitting a form.

However, CSRF protection doesn't apply to state-changing logic that runs automatically during page load. Examples include:

  • DML operations that execute even before the page fully renders.
  • Methods called from the action attribute in Visualforce pages.
  • Component initialization code performing DML in Aura, LWC, or Visualforce.

Secure Visualforce Pages

Apex methods called in the action attribute on<apex:page> or in a controller’s constructor run on page load and bypass CSRF protection. To secure your data, use user-triggered DML instead of auto-triggered initialization.

  • Avoid DML during page load: Trigger DML operations only in response to explicit user actions.
  • Avoid automatic method calls: Don't call apex:actionFunction methods via JavaScript events such as onload.

If a Visualforce page load requires DML, select Require CSRF protection on GET requests . To know more, see Create Visualforce Pages.

Note

Review the following example of auto-triggered DML. Since the init method runs during page load, it bypasses platform CSRF protections.

1<apex:page controller="myClass" action="{!init}"/>
2public class myClass {
3    public void init() {
4        Id id = ApexPages.currentPage().getParameters().get('id');
5        Account acc = [SELECT Id FROM Account WHERE Id = :id];
6        delete acc;
7    }
8}

To secure the page against CSRF attacks, require explicit user interaction to trigger state-changing logic. In this example, the deleteAccount method runs only when the user clicks Delete.

1<apex:page controller="mySafeClass">
2    <apex:form>
3        <apex:inputText value="{!accountId}" />
4        <apex:commandButton action="{!deleteAccount}" value="Delete" />
5    </apex:form>
6</apex:page>
7
8public class mySafeClass {
9    public String accountId { get; set; }
10    public void deleteAccount() {
11        Account acc = [SELECT Id FROM Account WHERE Id = :accountId];
12        delete acc;
13    }
14}

Secure Aura and LWC

Don't perform DML or state-changing operations during component load. When you use init, connectedCallback, renderedCallback, or a constructor, perform only read-only operations to fetch data. State-changing actions require explicit user interaction.

Review this example of auto-triggered DML in an Aura component. Because the doInit initialization handler modifies server data on component load, it bypasses platform CSRF protections.

1({
2    doInit: function(cmp) {
3        var action = cmp.get("c.updateField"); // Modifies server data on load
4        action.setParams({
5            recordId: cmp.get("v.recordId"),
6            newValue: cmp.get("v.newValue")
7        });
8        $A.enqueueAction(action); // Runs without user action — CSRF-prone
9    }
10})

To secure the component against CSRF attacks, perform only read-only operations during initialization and require explicit user interaction to modify data.

1({
2    doInit: function(cmp) {
3        var action = cmp.get("c.getSomething"); // Safe: read-only fetch
4        action.setCallback(this, function(response) {
5            if (response.getState() === "SUCCESS") {
6                // Safe display logic
7            }
8        });
9        $A.enqueueAction(action);
10    },
11
12    handleClick: function(cmp, event) {
13        var action = cmp.get("c.updateField"); // Safe: user-triggered
14        action.setParams({
15            recordId: cmp.get("v.recordId"),
16            newValue: cmp.get("v.newValue")
17        });
18        action.setCallback(this, function(response) {
19            if (response.getState() === "SUCCESS") {
20                // Show success / update UI
21            }         });
22        $A.enqueueAction(action);
23    }
24})

Secure Third-Party API Integrations

When you integrate a Lightning app with a third-party application via API, you can design custom anti-CSRF tokens. Add these to an XMLHttpRequest using setRequestHeader(). Here's an example.

1var o = XMLHttpRequest.prototype.open;
2XMLHttpRequest.prototype.open = function(){
3    var res = o.apply(this, arguments);
4    var err = new Error();
5    this.setRequestHeader('anti-csrf-token', csrf_token);
6    return res;
7};