4

We have a community portal built off of Visualforce pages and on those pages we do a lot of Javascript Remoting. Due to the complexity of our org, most of the Apex classes holding these remote methods are set to "without sharing" to bypass Salesforce's profile level and object security.

For example, one remote method will accept a "userID" string passed through the remote method. Once the remote method is called, it takes that ID that is passed and performs work on it.

Our security team brought up an issue where someone can use an external tool (like Fiddler) to record the remote calls and then re-submit them. In doing so, security can pass whichever user ID they would like and our Apex remote method will take that User ID without issue (since there is no security being enforced). Normally we control which users a user can perform work on through our UI logic - but by using a tool to record and re-submit, they can bypass the UI entirely.

This means that one external user who is not in any way, shape, or form related to another can take that other's user ID and perform work on it.

Is there a way to validate a Javascript remote call is called from the Visualforce UI and not another tool? We cannot change the security here due to our org complexity so we cannot use Salesforce's security/sharing rules to tighten security. Right now our only potential solution is to go into each remote method and write custom logic to ensure the User ID being worked on is related to the user who is making the call. This is a pretty big task as we have thousands of remote calls and many of them accept parameters such as user Id, account Id, etc.

Does anyone know of anything we can do to tighten these remote calls?

2 Answers 2

4

If you can't tighten up security that way, you could at least encrypt the data you're using, making it challenging for anyone to do anything with it. For example, consider the following:

public String encryptParam(String key, String value) {
  Blob key = Crypto.generateDigest('SHA256',Blob.valueOf(UserInfo.getUserId()+key));
  Blob enc = Crypto.encryptWithManagedIV('AES256',key,Blob.valueOf(value));
  return EncodingUtil.base64Encode(enc);
}
public String decryptParam(String key, String value) {
  Blob key = Crypto.generateDigest('SHA256',Blob.valueOf(UserInfo.getUserId()+key));
  Blob dec = EncodingUtil.base64Decode(value);
  return Crypto.decryptWithManagedIV('AES256',key,dec).toString();
}

Using these two methods, you can encrypt and decrypt parameters that depend on the logged in user and the name of the key (case sensitive!). This means you can also change the parameter name in Apex for each method, resulting in the same Id having a variation based on the method being called. There's a lot of potential here with encryption.

5

Even if you could reliably authenticate that the incoming call came from a Visualforce page the next step would be to invoke the Javascript Remoting API from something like the browser's developer console. This is arguably easier than using fiddler, since it's using the exact same tools as your intentional Javascript remoting invocations.

Attempting to authenticate the client is as such highly unlikely to be successful, since you'd have to in turn somehow guarantee that all javascript run by that client was your exact unmodified code. That is, bluntly, not possible.

Given that you have effectively built and exposed an API endpoint for this logic (just, javascript centric instead of something like a REST API), and by design escalated the access it runs with, you do need to apply security in your Apex logic. You've already opted out of the platform's built in protections (which I'd argue is fine, without sharing code has plenty of uses) you are indeed on the hook to validate that your logic abides by whatever alternate security constraints you're expecting.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .