Newer Version Available
Protect Your Application from CSRF Vulnerabilities
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.
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};