Salesforce Developer Security Storingsendatacustomset

salesforce-developer-security

// Salesforce - Developer - Security - Storing Sensitive Data - Custom Settings:

Custom settings are similar to custom objects and enable application developers 
to create custom sets of data  exposed to the application cache for efficient 
access without the cost of repeated queries to the database. Developers often 
wish to use custom settings for secret storage due to this efficient access. 
There are several options for configuring a custom setting to store a secret:

1. Public Custom Setting (Local)
2. Protected Custom Setting (Local)
3. Public Custom Setting (Managed)
4. Protected Custom Setting (Managed)

Managed Versus Local: What Do These Mean For Secret Storage?

Managed packages are a form of deployment often used by partners on the 
Salesforce AppExchange. Apex classes, Visualforce pages, Apex triggers, 
Salesforce objects and other common forms of metadata are wrapped up in a 
managed package in order to allow the package to be deployed to any other 
Salesforce instance. Managed packages are created inside free developer orgs by 
naming the package and creating a unique namespace. The namespace created will 
differ from the local namespace, which is the default namespace of every 
Salesforce instance. By installing the managed package in another org, two 
namespaces will exist: the local namespace and a new managed package namespace. 
The namespace of a managed package comes with a few benefits:

1. Segregation from the local namespace (only global methods are reachable to 
   anything outside of the package namespace). 

2. Obfuscation of Apex code, and some internal components. Users in the local 
   namespace can only see global Apex methods and cannot debug namespaced code.

3. Ability to deploy package to any Salesforce org on any instance.

4. Ability to list the package on the AppExchange.

Our best practice secret storage solution will employ these properties of a 
managed package to great effect. It is also important to note that you do not 
need to be a partner in order to create a managed package, and a managed package 
does not need to be employed to the AppExchange (we do not have to upload our 
managed package to the AppExchange in order to use it for protecting secret 
information). Any free developer org has the ability to create and upload a 
managed package for private use.

Local Custom Settings:

Local custom settings are custom settings not included in a managed package with 
a namespace. There are two varieties of this kind of custom setting, public and 
protected. The protected flag only functions for managed custom settings, so 
functionally these options are identical when the custom setting is in the local 
namespace. We will go over the most secure version of a local custom setting 
below:

Most Restrictive Setup:

1. Local custom setting is of type "list" with at least one text field. 

2. Custom setting can be set to public or protected, setting to protected has 
   no effect outside of a managed package.

3. Access to the secret is handled by Apex only, in system mode.

Benefits:

1. Local custom settings are easy to configure (no code required).

2. Local custom settings are accessible by the application cache, so no SOQL is 
   required to access information.

Drawbacks:

1. Values stored in local custom settings are visible to anyone with the "View 
   Setup" permission (very common) or anyone with the "API Enabled" permission 
   (also very common)

2. Local custom settings do not have any CRUD, FLS, or Sharing, so are 
   functionally worse than sObject text fields.

Because local custom settings are available to anyone with the "API Enabled" 
permission, we do not recommend using public custom settings for anything but 
public data. Even community users with API access would have access to the 
values stored within a local custom setting.

Managed Public Custom Settings:

Managed public custom settings are functionally equivalent to local custom 
settings, and thus not suitable for storing secrets. We cover the most secure 
implementation of a managed public custom setting below, but this is identical 
to the previous page. Feel fre to move onto the next section for the best 
practice secure storage solution.

Most Restrictive Setup:

1. Managed public custom setting is of type "list" with at least one text field. 

2. Managed public custom setting is set to public.

3. Access to the secret is handled by Apex only, in system mode.

Benefits:

1. Managed public custom settings are easy to configure (no code required).

2. Managed public custom settings are accessible by the application cache, 
   so no SOQL is required to access information.

Drawbacks:

1. Values stored in managed public custom settings are visible to anyone with 
   the "View Setup" permission (very common) or anyone with the "API Enabled" 
   permission (also very common)

2. Managed public custom settings do not have any CRUD, FLS, or Sharing, so are 
   functionally worse than sObject text fields.

Because managed public custom settings are available to anyone with the "API 
Enabled" permission, we do not recommend using managed public custom settings 
for anything but public data. Even community users with API access would have 
access to the values stored within a managed public custom setting. For any 
kind of secret, look to the solution provided later in this section or at the 
very least, use an sObject text field which supports CRUD, FLS, and Sharing. 

Managed Protected Custom Settings:

Managed protected custom settings are considered the most secure place in 
Salesforce to store secrets, and thus are the "best practice" architecture for 
secret storage in this section. What makes a managed protected custom setting 
so great for storage? Remember back to the earlier slide, where we stated that 
the managed package namespace comes with some advantages, including segregation 
from the local namespace. This means that anything happening in the managed 
package namespace will not be visible in the local namespace. The "protected" 
flag for the custom setting means that no person or code outside of the managed 
namespace can see or access the information stored in that custom setting, 
providing a walled garden inacessible to anything outside the managed package.

Consider the following setup, which is considered the "most restrictive" way to 
configure access to a managed protected custom setting:

Most Restrictive Setup:

1. Managed protected custom setting is of type "list" with at least one text 
   field. 

2. Managed protected custom setting is set to protected.

3. Access to the secret is handled by Apex only, in system mode, inside the 
   managed package. 

Benefits:

1. Managed protected custom settings are easy to configure (no code required).

2. Managed protected custom settings are accessible by the application cache, so 
   no SOQL is required to access information.

3. Managed protected custom settings are only accessible by code in the managed 
   package namespace. Code in the local namespace will never have access to the 
   managed protected custom settings of installed packages. This gives us a 
   solution that, when designed correctly, cannot be circumvented by users who 
   can deploy code, modify their profile, or deploy other AppExchange packages. 

4. Any malicious attempt to access the secret in a managed protected custom 
   setting would require an update to the managed package, and a deployment of 
   the updated managed package to the targeted instance. Since these duties can 
   be seperated across different roles, it is much less likely than a single 
   compromised account will be able to make all these steps undetected 
   (especially since two seperate Salesforce accounts are required, one for the 
   managed package edit and one for the production deployment).

5. The managed protected custom setting will not even be visible to anyone in 
   the local namespace (which is everyone). Attackers won't be able to identify 
   where the secret is stored unless they can gain access to the developer org 
   where the managed package was created.

Drawbacks:

1. Managed protected custom settings require a managed package, which requires 
   some additional overhead and management. 

2. Custom settings have a default storage limit of 10mb, so the solution is not 
   right for storing large amounts of data.

Managed protected custom settings are the winner for storing secrets in terms 
of flexibility and level of protection provided. When done correctly, not even 
administrators with "Modify All Data" can leak the secret. We recommend managed 
protected custom settings as the best practice secret storage solution for all 
high value secrets, like passwords and encryption keys.

To setup the debug log, open Setup -> Logs -> Debug Logs and add logging for 
your current user (System Administrator). Once saved, open the filters and c
hange the Apex code filter to "Finest."

The demo section contains two inputs, corresponding to: 

1. SecretCustomSetting__c.value__c (local custom setting)
2. SecureStorage__Secret__c.value__c (managed custom setting).

Both of the custom settings are flagged as protected.

The apex controller ignores running user's Sharing, CRUD and FLS settings and 
ensures the secret is never output in clear text to the page.

The buttons allow you to store or update the secrets, then return masked values 
to the page.

The purpose of this demo is to compare managed protected custom settings with 
local protected custom settings in regards to secret storage.

1. Open Setup -> Logs -> Debug Logs and add logging for your current user.
   a. Open the filters and set the debug log Apex code filter to: FINEST

2. Return to this demo page and set the secret values (or update them if they are 
   already set).

3. In the debug log entries, you will see the values for the local protected 
   custom setting are leaked, but the managed protected custom setting are not.

4. Next, use Workbench to attempt to query for protected custom settings, 
   SecretCustomSetting__c and SecureStorage__Secret__c. You will immediately 
   notice that SecretCustomSetting__c is visible but SecureStorage__Secret__c is 
   not. This is because protected custom settings are only visible to users and 
   code in the same namespace.

   a. As a local user, you can see and interact with any local protected custom 
      settings.

   b. As a local user, you cannot see or interact with any managed protected 
      custom settings in other namespaces.

5. To simulate what an attacker might do to leak a secret as a privileged user, 
   we have created a sample Apex class that can be invoked from the developer 
   console. Click this link and follow the instructions in the Apex class.

   a. The local custom setting can be accessed via local Apex code.
   b. The managed public custom setting can be accessed via local Apex code.
   c. The managed protected custom setting cannot be accessed via local Apex 
      code. You will see even if you attempt to compile code that accesses a 
      managed protected custom setting!

6. When you take all these steps into consideration, it is clear to see that 
   local protected custom settings can leak their secrets to the debug log, 
   through the API, and via Apex code. Managed protected custom settings are 
   immune to all these methods, and represent an excellent method for storing 
   secrets.

7. You can view the unobscured contents of the managed package in this file. We 
   will review the managed protected custom setting solution in more detail in 
   the next demos.

// Custom_Setting_Secret_Leaker_Demo:
public class Custom_Setting_Secret_Leaker_Demo{
    public void leakSecrets(){

        /* 
        The following code will leak the secret from a local protected custom 
        setting. Uncomment it and quick save!
        */
        //List<SecretCustomSetting__c> LocalCSList = 
        //new List<SecretCustomSetting__c>([select value__c from 
        //      SecretCustomSetting__c]);
        //system.debug(LocalCSList);

        /* 
        The following code will leak the secret from a managed public custom 
        setting. Uncomment it and quick save!
        */
        //List<SecureStorage__public__c> ManagedCSList = 
        //SecureStorage__public__c.getall().values();
        //system.debug(ManagedCSList);         

        /*
        The following code will leak the secret from a managed protected custom 
        setting. Uncomment it and quick save!
        */
        //List<SecureStorage__secret__c> ManagedPCSList = SecureStorage__secret__c.getall().values();
        //system.debug(ManagedPCSList); 

    }
}

// Custom_Setting_Secret_Storage_Demo:
public class Custom_Setting_Secret_Storage_Demo {

/******

Local Protected Custom Setting Code

******/

private static final String SECURE_STORAGE_DEMO_LocalCustomSetting = 
'Local Custom Setting Demo';
private SecretCustomSetting__c localCustomSetting {get;set;}
public transient string newLocalCustomSettingSecret {get;set;}

public string getLocalCustomSettingSecret(){
    if(localCustomSetting == null){
        List<SecretCustomSetting__c> secret = new List<SecretCustomSetting__c>();
        secret.add(SecretCustomSetting__c.getInstance(System.UserInfo.getUserId()));
        if (secret.size() == 1){
            localCustomSetting = secret[0];
        }else{
            localCustomSetting = new SecretCustomSetting__c(name = 
                SECURE_STORAGE_DEMO_LocalCustomSetting);
        }
    }
    string secret = '';
    if (localCustomSetting != NULL && localCustomSetting.value__c != NULL){
        if(Apexpages.currentPage().getParameters().get('showsecret') == 'true'){
            secret = localCustomSetting.value__c;
        }else{
            secret =  '****************';
        }
    }
    return secret;  
}

public void setLocalCustomSettingSecret(){
    if(newLocalCustomSettingSecret == NULL || 
        newLocalCustomSettingSecret.trim() == '') return;
    localCustomSetting.value__c = newLocalCustomSettingSecret;  
    upsert localCustomSetting;
    newLocalCustomSettingSecret = '';
}

public id getPrimaryAttachID(){
    FileStorage__c f = [
        select id from FileStorage__c 
        where name = 'Primary Package Record' limit 1];
    id attachmentID = [select id from attachment where parentid=:f.id limit 1].id;
    return attachmentID; 
}
}

To simulate what an attacker might do to leak a secret as a privileged user, we 
have created a sample Apex class that can be invoked from the developer console. 
Using the link in the demo, edit the Apex class.

Inside the Apex class you will notice that code is already compiled to leak 
secrets from the local protected custom setting and a managed public custom 
setting. There is code to leak managed protected custom setting secrets but it 
is commented out. Removing the comments, and attempt to save the code. 

When saving, you will encounter a compile error. This is because the Apex code 
you are saving is not in the same namespace as the protected custom setting you 
are attempting to access with your code.

1. The local custom setting can be accessed via local Apex code.
2. The managed public custom setting can be accessed via local Apex code.
3. The managed protected custom setting cannot be accessed via local Apex code.

When you take all these steps into consideration, it is clear to see that local 
protected custom settings can leak their secrets to the debug log, through the 
API, and via Apex code. Managed protected custom settings are immune to all 
these methods, and represent an excellent method for storing secrets.

1. Managed Protected Custom Setting (preferred / most secured)

   a. Pros: When used correctly, secrets are not available to be leaked to 
      anyone. This is the best practice approach for secret storage in 
      Salesforce. Scales using Apex encryption.

   b. Cons: Requires creation and maintenance of a managed package, which is 
      more overhead than a normal Apex solution.

2. Managed Public Custom Setting

   a. Pros: Easy to access through Apex.

   b. Cons: Requires creation and maintenance of a managed package. Due to a 
      lack of CRUD, FLS, Sharing, and availability outside of the managed 
      package these values are visible to any users with API access.

3. Local Protected Custom Settings

   a. Pros: Easy to create, and easy to access through Apex.

   b. Cons: Protected flag has no effect due to lack of namespace.  Without 
      CRUD, FLS, Sharing these values are visible to any users with API access.

4. Local Public Custom Settings

   a. Pros: Easy to create, and easy to access through Apex.

   b. Cons: Without CRUD, FLS, Sharing these values are visible to any users 
      with API access.

Taking into account the strengths and weaknesses above, managed protected custom 
settings (when used correctly) are appropriate for the highest levels of 
sensitivity, including administrator passwords and encryption keys. Managed 
public custom settings, local protected custom settings, and local public custom 
settings are not appropriate for secrets of any kind, and should only be used 
with public information.

Using Managed Protected Custom Settings:

As you may have come to realize, storing secrets is only part of the overall 
solution for protecting them howevever. If your secret is something like a 
password or encryption key, you are eventually going to want to use it. This 
section is all about properly architecting a secure secret storage solution 
using a managed protected custom setting and all the other secret protection 
best practices we can provide.

Accessing Secrets In Managed Packages:

In the custom setting section, we made it clear that the local user cannot 
access a protected custom setting inside a managed package, because the local 
user is not in the same namespace as the protected custom setting. So how were 
we able to store the secret using the button & input on the demo page? Apex 
and Visualforce offer two primary methods for interacting with a managed 
package from the local namespace:

1. Visualforce is viewable and usable from all namespaces.

2. The global access modifier in Apex makes any class known by all Apex code 
   everywhere, including other namespaces.

The security and strength of your secret storage solution depends on how you 
use these options. Consider a scenario where you need make a callout and 
authenticate to an API external to Salesforce. You've built a managed package 
with a protected custom setting called "protectedCustomSetting" to store the 
secret, and you are accessing it outside of your managed package with the 
following code:

Global class SecretAccess{ 
  public string getSecret(){
    return secret = [select secret__c from protectedCustomSetting 
        limit 1].secret;
  }
}

This approach compromises many of the benefits provided by the managed 
protected custom setting solution. The secret can now be accessed from any 
namespace by anyone who can run Apex code (by deploying or using the developer 
console). The secret can also be leaked to the debug log.  

Best Practice Approach to Accessing Secrets In Managed Packages;

This brings us to our best practices for accessing secrets in managed packages:

1. User interaction with a secret like setting, or updating the secret should 
   be done through a Visualforce page or component inside the managed package. 

2. Any functionality that uses the secret, like a callout function or an 
   encryption function, needs to be contained within the managed package.

3. Invoking the functionality that uses the secret can be done with a global 
   method, but the secret should never be returned outside of the managed 
   package.

In the custom setting demo you previously completed we demonstrated the first 
two bullets. User interaction to set the secret was done through a managed 
Visualforce component embedded on a local Visualforce page, and all the 
functionality to update the secret was contained within the managed package. 
We will further demo this correct architecture in the coming demo on secret 
usage.

We have seen several partners attempt to create a secret storage offering that 
stores and returns passwords and encryption keys using global methods. This 
approach is never secure, and never passes AppExchange security review. Any 
password solution must contain all the necessary functionality inside the 
managed package.

Secret Dependencies:

Secret dependencies exist when the secret is linked to another piece of 
information. The security of the secret can be compromised if that dependency 
is not handled correctly. The primary example of this is a the endpoint of an 
httpRequest that requires authentication. Consider the following code inside a 
managed package:

Global class sampleCallout {
  public string doCallout(string url){
    ProtectedCustomSetting__c pcs = [
        select username__c, password__c from ProtectedCustomSetting__c limit 1];
    HttpRequest req = new HttpRequest();
    req.setEndpoint(url);
    req.setHeader('Authorization', 'Basic '+
        EncodingUtil.base64Encode(Blob.valueOf(pcs.username__c + ':' + 
        pcs.password__c)));
    return new http(req).getBody();
  }
}

This class is an example of a standard httpRequest with Basic authentication, 
where the username and password are retried from a protected custom setting. 
This is also a highly insecure example. Do you see why?

The class is global, so anyone in the local namespace with the right permissions 
can invoke the callout (this is fine). The return of the http callout method 
(which can be viewed outside of the managed package) is the response body which 
does not include the password (this is great). The problem is that the 
httpRequest endpoint can be set outside of the managed package via "string url" 
when invoking the method. If an attacker could specify a URL that he controlled, 
like http://attackerwebsite.com, he could recieve the callout with the 
authentication header, and he would have effectively leaked the password. For 
callouts like httpRequests, the password is dependent on the URL! This is a 
very similar to the named credentials weakness we outlined in the named 
credentials demo.

To mitigate this issue, the code would be much more secure as follows:

Global class sampleCallout {
  public string doCallout(){
    ProtectedCustomSetting__c pcs = [
        select username__c, password__c, url__c 
        from ProtectedCustomSetting__c limit 1];
    HttpRequest req = new HttpRequest();
    req.setEndpoint(pcs.url__c);
    req.setHeader('Authorization', 'Basic '+
        EncodingUtil.base64Encode(Blob.valueOf(pcs.username__c + ':' + 
        pcs.password__c)));
    return new http(req).getBody();
  }
}

Now the URL comes from the same protected custom setting as the password, and is 
no longer controllable from outside the managed package. 

Secret Dependency Best Practices:

Now that you understand the issue with secret dependencies, let's discuss best 
practices to mitigate the issue:

1. Secrets and the values they depend on should be controlled from the same 
   place (the same managed package for example). This is often easiest if they 
   are stored together, but not always necessary.

2. If the value the secret depends is updated, an update to the secret should 
   be enforced. This prevents a current secret from being leaked in any way. 
   If the secret changes, the value it depends on does not need to be changed. 

Avoiding Secret Reflection:

Secret reflection occurs when a secret is returned to client, and is considered 
a security vulnerability. In Salesforce, we often see this when a password is 
returned to a Visualforce page. Consider the following sample code:

Visualforce:

<apex:commandButton action="{!storeSecret}" value="Update"/>
<apex:inputSecret value="{!inputSecret}"/>

Apex:

public string inputSecret {get; set;}
protectedCustomSetting pcs;

public void storeSecret(){
  pcs.value__c = inputSecret;
  upsert pcs;
}

InputHidden is often misunderstood. Although the secret may appear to be 
obscured on the page, this is only a rendering trick. If you view the source 
code, the secret will be 100% visible. To avoid secret reflection, use the 
Apex keyword "transient" instead.

The documentation defines the transient keyword as "used to declare instance 
variables that can't be saved, and shouldn't be transmitted as part of the view 
state for a Visualforce page." The view state portion of that definition is also 
very important. Since HTML is a stateless protocal, viewstate is used to hold 
all your state information, like public variable values, on the client side (in 
your browser). Viewstate is encrypted to prevent snooping, but it is considered 
a security best practice to never reflect secrets into the viewstate so that 
even if the viewstate encryption is compromised, your secrets are not. 

Here is a better version of the previous sample code:

Visualforce:

<apex:commandButton action="{!storeSecret}" value="Update"/>
<apex:inputSecret value="{!inputSecret}"/>

Apex:

public transient string inputSecret {get; set;}
protectedCustomSetting pcs;

public void storeSecret(){
  pcs.value__c = inputSecret;
  upsert pcs;
}

Now, with the transient keyword, the protected custom setting will be updated, 
but the inputSecret variable will be cleared on viewstate postback. No more 
secret reflection! 

Scaling With Encryption:

Protected custom settings inside managed packages are perfect for most 
situations, but not all. Custom settings have an org-wide limit of 10mb, which 
means they may not be suitable for mass data storage. If you needed to store 1 
million credit cards in a secure location on the Salesforce platform, you might 
encounter issues with custom settings. 

Enter Apex encryption!  Apex supports cryptography through the Apex crypto 
class, which provides a number of cryptographic functions for creating digests, 
message authentication codes, and signatures, as well as functions for 
encrypting and decrypting information. These functions allow you to protect the 
confidentiality of data as well as allow external systems to verify the 
integrity of messages and authenticity of the sender. Using Apex encryption, a 
crypto key can be stored inside a managed protected custom setting, and used to 
encrypt and decrypt data for use within the managed package. 

Here is a code sample from the Salesforce documentation using the Apex crypto 
class:

Blob cryptoKey = Crypto.generateAesKey(256);
Blob data = Blob.valueOf('Test data to encrypted');
Blob encryptedData = Crypto.encryptWithManagedIV('AES256', cryptoKey, data);
Blob decryptedData = Crypto.decryptWithManagedIV('AES256', cryptoKey, encryptedData);
String decryptedDataString = decryptedData.toString();

The cryptoKey variable could be stored and retrieved from a managed protected 
custom setting. 

If the managed package has global encrypt and decrypt methods, a user with 
access to Apex could encrypt and decrypt data at will. For a solution involving 
cryptography, it is best to keep the encryption, decryption, and plain text data 
all within the managed package for maximum security. The package should only 
ever return encrypted values, never decrypted!

The demo below contains a sample "payment processing" application, built using 
local and managed Force.com code.  URL and Secret storage are done inside the 
"Secure Secret Storage" managed package with the "SecureStorage" namespace.  
Credit card, payee, amount, and note fields are all handled locally.

The "Process Payment" button invokes the 
SecureStorage.PaymentProcessor.setAccessTokenAndSend(HTTPRequest) method. 

1. This method is in the "SecureStorage" namespace, and is marked global, 
   allowing access from the local namespace.

2. This method accepts an apex HTTP Request, adds the URL, injects the 
   authentication information into the header, executes the callout, and returns 
   the response.

A sample webservice endpoint has been created, which requires an access token 
for authentication. 

The purpose of this demo is to illustrate the dangers of improperly handling a 
secret dependcy (in this case between a secret and a URL). Walk through the demo 
steps below to illustrate the risk. 

1. To begin, follow this link to generate your api key / secret.

2. Next, store your newly generated api key in the secret field.

3. When you generated the key, you may have noticed some documentation on 
   available API calls. We want to submit a payment, so we'll want to store the 
   following URL: 
   https://banditpayment-developer-edition.na12.force.com/services/apexrest/
   SecureStorage/payment

4. Now that we have stored a secret and a URL, it's time to fill out the rest 
   of the form. 

   a. Payee = Some imaginary company.
   b. Bandit Credit Card = A value in the format 99-[####], like 99-[1234].
   c. Amount = Some number.
   d. Payment Notes = Some text.

5. Once you have filled these items out, click submit, and you should see a 
   success message.

6. As the attacker, it is now time to try and exploit this form. Have the best 
   practices around password reflection been followed? Use your browser's view 
   source functionality to view the underyling HTML for this page.

7. Search for "newSecret", which will show you the field storing the secret. 
   The developer of this page mistakenly allowed for password reflection, and 
   your secret is leaked to anyone with access to the page!

8. Next, let's see if the developer properly handled the Password/URL dependency. 
   Make the following changes: 

   a. Change the URL to: https://trailheadhttpbin.herokuapp.com/headers
   b. Edit the Apex controller and change the HTTP method in processPayment() 
      from POST to GET.
   c. Edit the Apex controller and comment out the line with req.setBody in the 
      processPayment() method.

9. Fill in the details again to bypass the validation and submit the request 
   again. A successful request will leak the secret to the page (check the 
   headers for the authorization)!

10. Using either of these approaches, the attacker could learn the secret and 
    use it to make custom API calls to the endpoint following the documentation 
    potentially leaking the secret....

11. To walk through the full attacker experience, you can follow the 
    documentation to make an HTTPrequest from the Developer Console and leak all 
    the transactions (but this is not required).

12. Move on to the next demo when you are ready to see this solution secured.

Vulnerable_Secret_Usage_Demo:

/*
* Controller for SecretUse demo.  
* All secret management performed in managed component on the vf page.
* Demo's insecure USE of secrets for a payment processing api
*/

public with sharing class Vulnerable_Secret_Usage_Demo {

    public Payment payment  {get;set;}
    public String confirmation {get;set;}

    public Vulnerable_Secret_Usage_Demo(){
        payment = new Payment();
    }

    public String[] getPermSets(){
        String[] permSetArray = new List<string>();
        permSetArray.add('Demo User for SecretStorage.');
        return permSetArray;
    }

    public void processPayment(){

        HttpRequest req = new HttpRequest();

        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Accept', 'application/json');
        req.setHeader('charset', 'charset=UTF-8');

        /* Change the method from POST to GET */
        req.setMethod('POST');
        String body = JSON.serialize(payment);
        /* Comment this section out to exploit */
        req.setBody(body);
        /*-------------------------------------*/
        /* The above steps are only required because or fake attack URL only 
            accepts GET */

        HttpResponse res = 
            SecureStorage.PaymentProcessor.setAccessTokenAndSend(req);
        if(res.getStatusCode() == 200){
            confirmation = 'SUCCESS.  Confirmation # ' + 
                res.getBody().replace('"', '');
        }else{
            confirmation = 'ERROR. Status Code : ' + 
                res.getStatusCode() + '. Message : ' + res.getStatus();
        }
    }

    private class Payment{

        public Decimal amount {get;set;}
        public String banditCC {get;set;}
        public String payee {get;set;}
        public String notes {get;set;}    
    }

    public id getPrimaryAttachID(){
        FileStorage__c f = [
            select id from FileStorage__c 
            where name = 'Primary Package Record' limit 1];
        id attachmentID = [
            select id from attachment where parentid=:f.id limit 1].id;
        return attachmentID; 
    }    

}

The demo below contains a sample payment processing application, built using 
local and managed Force.com code.  Secret and URL storage are done inside the 
"Secure Secret Storage" managed package with the "SecureStorage" namespace.  
Credit card, payee, amount, and note fields are all handled locally.

The "Process Payment" button invokes the 
SecureStorage.PaymentProcessor.send(HTTPRequest) method. 

1. This method is in the "SecureStorage" namespace, and is marked global, 
   allowing access from the local namespace.

2. This method accepts an apex HTTP Request, adds the URL and authentication 
   information, executes the callout, and returns the response.

A sample webservice endpoint has been created, which requires an access token 
for authentication. 

The purpose of this demo is to illustrate a correctly built secret storage 
solution. You'll walk through the various components that are done correctly, 
then have access to the code to review! 

1. Follow this link to generate a new api key / secret and store it in the 
   secret field.

2. Next, store the following URL and click "Store Values":
   https://banditpayment-developer-edition.na12.force.com/services/apexrest/
   SecureStorage/payment

3. Now that we have stored a secret and a URL, it's time to fill out the rest 
   of the form:

   a. Payee = Some imaginary company.
   b. Bandit Credit Card = A value in the format 99-[####], like 99-[1234].
   c. Amount = Some number.
   d. Payment Notes = Some text.

4. Once you have filled these items out, click submit, and you should see a 
   success message.

5. As the attacker, it is now time to try and exploit this form again. Check 
   for password reflection using your browser's view source functionality.

6. Search for "newSecret", which will show you the field storing the secret. The 
   secret is no longer available!

7. Now try changing the URL to your attacker owned URL:
   https://trailheadhttpbin.herokuapp.com/headers

8. This time, you will see the error "Secret and Endpoint must both be set." To 
   prevent leaking the secret, they now must be changed together!

9. To review the managed package solution, you can export the source code with 
   this link. The noteworthy pieces are:

   a. SecretUseSolution - The Visualforce component where the secret and URL are 
      entered.
   b. SecretUseSolutionController - The Apex controller where the secret and URL 
      are moved to secure storage.
   c. PaymentProcessor - The Apex class, with global methods that are available 
      to the local namespace, that uses the secret to perform the callout.

10. Review the SecretUseSolution page and SecretUseSolutionController to see 
    that the the secret is not reflected, and the dependency is properly managed.

11. Review the PaymentProcessor class to see the global methods made available 
    to the local namespace. The secret is never leaked here.

12. You are now done with the secret storage demos. Review the conclusions in 
    Trust Academy, then move onto the next section!

Secret Use Conclusions:

You have now seen the importance of using secrets correctly. If not done well, 
secret usage can compromise the security of a secret entirely. Secret storage 
and use is never simple, and must be done thoughtfully and carefully. Always 
remember to keep in mind the following concepts:

1. Secrets inside managed packages should never leave the managed packages, 
   lest they lose the protection benefits of the namespace.

2. Be mindful of dependencies with your secrets. If a URL needs to be updated, 
   the secret should also be updated to prevent leaking the secret.

3. Secrets should never be reflected to the client or they might be leaked (if 
   the client is malicious or even curious).

4. Use Apex encryption to scale your secret storage and workaround storage 
   limits.

Secret Protection Conclusions:

For secret storage, Salesforce recommends the following solutions:

1. Managed Protected Custom Settings (best option)
2. Named Credentials

When using a secret, be sure to keep all of the following in mind: 

1. Secrets inside managed packages should never leave the managed packages, 
   lest they lose the protection benefits of the namespace.

2. Be mindful of dependencies with your secrets. If a URL needs to be updated, 
   the secret should also be updated to prevent leaking the secret.

3. Secrets should never be reflected to the client or they might be leaked (if 
   the client is malicious or even curious).

4. Use Apex encryption to scale your secret storage and workaround storage 
   limits.

To provide a quick reference on secret storage, we have stacked and ranked the 
options from the previous sections. 

1. Managed Protected Custom Setting

   a. Pros: When used correctly, secrets are not available to be leaked to 
      anyone. Scales using Apex encryption.
   b. Cons: Requires creation and maintenance of a managed package, which is 
      more overhead than a normal Apex solution.
   c. Best For: All types of secrets. Salesforce best practice choice for 
      storing secrets!

2. Named Credentials

   a. Pros: Easy to configure. The secret can only be set and updated by users 
      with Modify All Data.  The secret is not visible in UI. The secret + URL 
      are invoked together in Apex.
   b. Cons: Users with Modify All Data can update the URL and leak the secret. 
      Only usable for passwords and tokens, not encryption keys and more complex 
      secret solutions.
   c. Best For: Named credentials are appropriate for storing passwords and 
      tokens that are not considered to be highly sensitive (IE administrator 
      credentials)

3. sObject Encrypted Text Fields

   a. Pros: Encrypted at rest, Using CRUD, FLS, and sharing will obscure from 
      majority of users. Easy to setup.
   b. Cons: Not hidden from Modify All Data, Download AppExchange Packages, 
      Deploy Apex, View Encrypted Data.
   c. Best For: Sensitive data with compliance regulations requiring encryption 
      at rest.

4. sObject Text Fields

   a. Pros: Using CRUD, FLS, and sharing will obscure from majority of users. 
      Easy to setup.
   b. Cons: Modify All Data, Download AppExchange Packages, Deploy Apex, Manage 
      Profiles and Permission Sets, Customize Application, and View All Data.
   c. Best For: Normal, non-secret information.

5. Managed Public Custom Setting / Local Protected Custom Setting / Local Public 
   Custom Setting:

   a. Pros: Easy to create, and easy to access through Apex.
   b. Cons: Without CRUD, FLS, Sharing these values are visible to any users 
      with API access.
   c. Best For: Public information only (usually application configuration 
      settings).
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License