function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ca_peterson_oldca_peterson_old 

XSRF Mitigation suggestions

First of all, good work on adding XSRF (cross-site request forgery) to the security scanner.

 

Secondly, I'd like to ask for some tips on a more secure way of doing things.

 

Currently I have a button for a ticketing system that most compeditors have, one that takes ownership of the current record. Currently I have this implemnted as a visualforce page something like this:

 

 

<apex:page standardController="ticket__c" extensions="sObjectUtils" action="{!takeOwnership}">
<apex:outputPanel rendered="false">
<!-- here to let the standardController.getRecord() method rather than SOQL -->
	{!ticket__c.ownerId}
</apex:outputPanel>

Ownership taken.
</apex:page>

 

The problem is I can't see a way to put a button on a detail page that doesn't open me up to XSRF without requiring an exta step. I'd love it if I could call an action with a button directly, which would mitigate the XSRF issues, but that's currently not supported by the platfrom.

 

So mighty security gurus, what's the "proper" way of implementing this button?

 

Best Answer chosen by Admin (Salesforce Developers) 
BrendanOCBrendanOC

The web services API is not vulnerable to CSRF because the server ignores the session cookie and looks for the session in the SOAP envelope.  However, API responses are not escaped for XSS like VisualForce is, so you are responsible for that in your script.

 

Because you are using object IDs in Javascript, you won't have any XSS bugs in that function. (Object IDs are strongly typed)  However, if you are ever doing something similar with String values, you need to use the {!JSENCODE} and/or {!JSINHTMLENCODE} functions to perform character escaping.

 

Also, I'm not sure what data will be in your error message, but if a User can influence any piece of the that error message, use {!JSINHTMLENCODE(error)} to avoid potential XSS bugs.

 

 

All Answers

BrendanOCBrendanOC

Based on that code, I'm not sure that I fully understand what you're trying to do.  You want the user to click a button, and based on that action take ownership of a record?

 

If that's the case, you can do this securely a couple of ways.  One way would be to have a form that POSTs (Visualforce forms have automatic CSRF protection) and link your button to Javascript that does a form submit.  The form could pass the ID of the SObject, and the Apex class could change ownership based on the SObject ID and UserInfo.getUserId().  Just make sure that you're not breaking CRUD/Sharing when you change the owner of the record.  On the VisualForce page, you could tie the button to a Javascript submit with onclick=submitForm()

 

 

If you must use the query string or a GET request for some reason, you'll need to add your own nonce+identifier parameter and validate it.  You would need an Apex method to generate a token that consists of a random string + something unique (hashing the User ID with a Salt would work) and place it on the page.  When the user clicks the button, this value would be passed to the Apex controller, and the controller would need to validate this token.

 

The idea behind CSRF protection is to ensure that the user making the HTTP request intended to make it.  You need randomness to make sure the token can't be replayed or easily guessed, and you need some sort of unique identifier to tie the request to the user.

 

For more info, there's a section on CSRF protection in the Writing Secure Apps online training here:

http://salesforce.acrobat.com/writingsecureapps/

 

Hope that helps!

 

 

 

ca_peterson_oldca_peterson_old

It does a little bit, but I'm trying to make a button on a standard detail page take ownership in 1 click. I just realized I can probobly do that easier with the javascript tools than with visualforce, and without this issue.

 

If it was a custom VF page it would be easy to make it behave like I want, the much trickier part is doing it from a standard page, let me try it using the salesforce ajax toolkit and see if that has better results.

ca_peterson_oldca_peterson_old

I switched to using a javascript button rather than a visualforce button for this, and I think for a one-click operation that makes more sense anyways. Just got the security scanner results back and showing all is well with this method.

 

For anybody curious, here's the javascript button source:

 

{!REQUIRESCRIPT("/soap/ajax/18.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/18.0/apex.js")}

var user = sforce.connection.getUserInfo();

var recordId = "{!namespace__object__c.Id}";
var ownerId = user.userId;
var objType = "namespace__object__c";

var result = sforce.apex.execute("namespace.sObjectUtils","takeOwnership",{recordId:recordId, ownerId:ownerId, objectType: objType},{ onSuccess : success, onFailure : failure} );



function success(result){
window.location.href = window.location.href;
}
function failure(error) {
alert("An error has occurred " + error);
}

 

I don't see any vulnerability in this method, but correct me if I'm wrong, please!

 

 

 

BrendanOCBrendanOC

The web services API is not vulnerable to CSRF because the server ignores the session cookie and looks for the session in the SOAP envelope.  However, API responses are not escaped for XSS like VisualForce is, so you are responsible for that in your script.

 

Because you are using object IDs in Javascript, you won't have any XSS bugs in that function. (Object IDs are strongly typed)  However, if you are ever doing something similar with String values, you need to use the {!JSENCODE} and/or {!JSINHTMLENCODE} functions to perform character escaping.

 

Also, I'm not sure what data will be in your error message, but if a User can influence any piece of the that error message, use {!JSINHTMLENCODE(error)} to avoid potential XSS bugs.

 

 

This was selected as the best answer
ca_peterson_oldca_peterson_old

Awesome, thanks for the help!

p999_dfsp999_dfs

We have similar issue with Cross-Site Request Forgery (CSRF) for some of our VF pages.

 

VF page code

 

 

<apex:page controller="Invoice_Con" action="{!attach_Invoice}">
    Processing.......
</apex:page>
		

 

 

 

Apex controller

 

global with sharing class Invoice_Con {

   //attach invoice 
    global PageReference attach_Invoice() {
        // Get the page definition 
        PageReference pdfPage = Page.OrderInvoice;

        // set the Invoice id on the page definition 
        pdfPage.getParameters().put('id',id);

        // generate the pdf blob 
        Blob pdfBlob = pdfPage.getContent();
        
        //create the attachment for Invoice 
        Attachment a = new Attachment(parentId = id, name='Inv-00001' + '.pdf', body = pdfBlob);
        insert a;     
        return null;
   }

}

 

 

what is the best way to avoid issue with Cross-Site Request Forgery (CSRF). We do not want to introduce another intermedeiate page for confirmation. We need to make a public release and the security scanner is keep failing our codes for

 

thanks

 

ca_peterson_oldca_peterson_old

There's two ways to approach this that I can see.

 

First, you can embed javascript calling a webservice method rather than using a page action, which isn't vulnerable to XSRF.

 

But considering the action doesn't take any user input, and only attaches PDF that they have no control over the rendering of you may be able to get an exception from the security team. If you can answer the question "could loading this page with malicious data do damage to my data?" with a solid no, then I think they would grant an exception.

 

But I'm by no means an XSRF expert, so I may be wrong. If you're looking for the easy way out you can do some javascript similar to what I posted and put it into an onload handler.

highland23highland23

Hi p999_dfs,

 

I'm curious as to how your security review process went with your situation.  We'd be interested in doing something similar, but are looking to see if there's any other alternatives to the approach you took in this thread.

 

Cheers!