📢 Attention Salesforce Certified Trailblazers! Maintain your credentials and link your Trailhead and Webassessor accounts by April 19th. Learn more.
close
•
Start tracking your progress
Trailhead Home
Trailhead Home

Identify CRUD and FLS Violations in Visualforce and Apex

Learning Objectives

After completing this unit, you’ll be able to:

  • Define CRUD and FLS.
  • Identify CRUD and FLS violations in Visualforce and Apex.

What Are Create, Read, Update, and Delete (CRUD) and Field Level Security (FLS)?

As you may recall from the previous unit, CRUD and FLS are authorization settings that let Admins specify which objects and which fields on an object a user can access and modify.

Below are some examples of what this looks like in our Kingdom Management developer org.

Screenshot of the CRUD granted for custom objects in the Kingdom Management developer org  

As you can see, the Admin has put different access restrictions for this user in our org. The user can read a number of different objects but only has authorization to modify a small subset. 

The admin has also configured FLS for different objects. Here are the fields for the Treasures__c object. 

Screenshot of the FLS configured for the Treasure object in the Kingdom Management developer org

While this user can read the object itself (via CRUD settings), the user can only see some fields (like Name and Description) but not others. 

How Are CRUD and FLS Enforced in Force.com Apps?

In the Kingdom Management developer org, our admin has configured CRUD and FLS for the various objects and fields. It’s now our job as developers to ensure that our custom apps respect these settings. As we learned, there are two modes in which the platform executes code: system context and user context. How do these modes work with custom apps?

CRUD and FLS in Visualforce

In the previous unit, we learned that a Visualforce page using a standard controller run in user context. Therefore by default it enforces CRUD and FLS restrictions. 

For example, if the user has read access for both the Contact object (CRUD) and the Contact object email field (FLS), then the below data is rendered.

  <apex:page standardController=”Contacts”>
    <apex:outputField>{!contact.Email}</apex:outputField>
  </apex:page>

But this is a very simplistic example. Most apps that developers create for the platform rely on custom controllers or extensions to standard controllers. So how does CRUD and FLS enforcement work in these cases? 

The answer unfortunately is...it depends. Let’s find out why.

Exploring CRUD and FLS Enforcement in Custom Visualforce

Let’s see what this looks like in our Kingdom Management org.

  1. Log in to the Kingdom Management org.
  2. Select the CRUD/FLS & Sharing app from the App Picker.
  3. Click the CRUD & FLS Visualforce Demo tab.

    Screenshot of the CRUD & FLS Visualforce Demo app

    In this app, you see a custom Visualforce page that lists treasure that has been discovered throughout the kingdom. You want to keep this data secret, so let’s make sure that CRUD and FLS is properly being enforced.

    Using the dropdown in the top left of the app, you can simulate users with different levels of CRUD and FLS access and observe what data the app shows each user. Let’s try this now.

  4. From the drop-down menu, select User with Limited Access to Treasures.

    Below is this user’s permission set, which grants access to only a small subset of fields on the Treasures object. This user can see some information about a piece of Treasure, but not whether it’s been found or where it’s being stored.
    Screenshot showing the CRUD and FLS granted to the user for the Treasures object

    Once you select the user from the dropdown, the page refreshes and you see a screen similar to what you see in this graphic.
    Screenshot of the CRUD & FLS Visualforce Demo app showing data leak

    In the Direct Reference table, the data is restricted as expected. The Found column is false for everything and the Castle column is blank. However, in the Dereferenced table, you see fields that the user is unauthorized to access. Why? Let’s take a look at the code for the first table, where things were properly restricted.

  5. Click the Return to user selection... button to return to the Admin user.
  6. Click the Visualforce page link at the bottom to see the source for the page.

    You see this code.
        <h3>Discovered Treasure - Direct Reference</h3>
        <apex:pageBlockTable value="{!treasures}" var="p">
          <apex:column headervalue="Name">
            <apex:OutputText value="{!p.Name}" />
          </apex:column>
          <apex:column headervalue="Description">
            <apex:OutputText value="{!p.Description__c}" />
          </apex:column>
          <apex:column headervalue="Found">
            <apex:OutputText value="{!p.Found__c}" />
          </apex:column>
          <apex:column headervalue="Castle">
            <apex:OutputText value="{!p.Castle__r.Name}" />
          </apex:column>
        </apex:pageBlockTable>
          
    This table displays the object fields using standard object notation--{!p.Name}, {!p.Description__c}, {!p.Found__c}, {!p.Castle__r.Name}--so by default the platform enforces any CRUD and FLS restrictions. This is why, just as we expected, the sensitive fields are not displayed.

    But what about the second table? Let’s take a look at what is happening there.
          <h3>Discovered Treasure - Dereferenced</h3>
          <apex:pageBlockTable value="{!dereferencedTreasures}" var="p">
            <apex:column headervalue="Name">
              <apex:OutputText value="{!p.Name}" />
            </apex:column>
            <apex:column headervalue="Description">
              <apex:OutputText value="{!p.Description}" />
            </apex:column>
            <apex:column headervalue="Found">
              <apex:OutputText value="{!p.Found}" />
            </apex:column>
            <apex:column headervalue="Castle">
              <apex:OutputText value="{!p.Castle}" />
            </apex:column>
          </apex:pageBlockTable>
        
    In this table, we loop through a list called dereferencedTreasures and return the results. If we go to Apex, we can see what this list contains.

  7. Navigate back to the app and click the Apex Controller link at the bottom.
          public with sharing class CRUD_Demo {
            public List<TreasureWrapper> dereferencedTreasures {get;set;}
            [...]
            public with sharing class TreasureWrapper {
              public Treasures__c treasure {get; private set;}
              public TreasureWrapper(Treasures__c treasure) {
                this.treasure = treasure;
                }
              public String getName(){
                return treasure.Name; // CRUD & FLS Violation
              }
              public Boolean getFound(){
                return treasure.Found__c; // CRUD & FLS Violation
              }
              public String getDescription(){
                return treasure.Description__c; // CRUD & FLS Violation
              }
              public String getCastle(){
                return treasure.Castle__r.Name; // CRUD & FLS Violation
              }
            }
          }
              
    The app uses a wrapper class around the Treasures__c object called TreasureWrapper. A list of these custom objects are returned to Visualforce. The class defines several custom getter methods such as getFound, which simply return the string or Boolean values of each of the Treasures__c object fields.

    So when Visualforce is asked to render
    <apex:OutputText value="{!p.Found}" />

    In Apex the getFound() function in TreasureWrapper is called, which returns a string representation of the Treasure__c.Found__c field. This string is then sent back to Visualforce to be rendered. In this case, Visualforce is being asked to render a string and not an object field (unlike the first table, which rendered the object). Therefore, all the CRUD and FLS settings that are tied to the object and field are now lost. When rendering primitive types, Visualforce doesn’t have the additional context, so it renders strings regardless of access restrictions placed on the user. Oh, no!

So, depending on how the data is rendered in Visualforce, users can see information they don’t have authorization to access. 

CRUD and FLS in Apex

Now that we’ve seen the issues with rendering data in Visualforce, let’s talk about modifying and creating data. How is CRUD and FLS enforced for code that runs server side?

Remember, Apex classes, Apex triggers, and Apex web services all execute in system context. This means that by default Apex has access to all data, regardless of the user’s access restrictions.

  • Any object or object field can be queried.
  • Insert(), Update(), and Delete() can be called for any object or field.

Exploring CRUD and FLS Enforcement in Apex

Let’s explore this in our org.

  1. Click the CRUD & FLS Apex Demo tab.

    Screenshot of the CRUD & FLS Apex Demo app

    In this app, you see a list of supply requests from throughout the Kingdom. We want to make sure that only authorized users can view and remove these requests. If we don’t, a raiding party could use this app to potentially prevent supplies from entering a castle under siege, or worse!

    So let’s test it out. Similar to the previous app, you can simulate different users via the drop-down menu.

  2. Select User with Read ONLY Access.

    Below is the permission set applied to this user. As you can see, the user can read but can’t modify supply requests. For supply requests we use the Requisition__c object.
    Screenshot showing only read access has been granted to this user


  3. Back in the app, click any of the Del links on the right side to remove a record from the system.

    Oh, no! The user deleted the record. How did that happen, when the user has read-only access? Let’s investigate.

  4. Press Return to User Selection to return to the admin user.
  5. Click the Apex Controller link at the bottom of the page.

    Let’s take a look at the Apex function that is called when we clicked on the Del link in Visualforce.
          public PageReference deleteRequest(){
            Requisition__c delr = [select id from Requisition__c where id =: id limit 1];
            if(delr != null) {
              try{
                delete delr;
              }
              catch(DmlException ex){
                  ApexPages.addMessages(ex);
              }
            }
            return null;
          }
    This function uses the ID of the record that was selected to remove it from the database. Remember that Apex runs in system context. This means that Apex can modify any record, regardless of the running user’s access level. So while our user has only read access to the Requistion__c object, when the deleteRequest function is called, Apex deletes the object instance without verifying CRUD/FLS for the user.

So as we’ve seen in these simple demos, you need to be careful about how you render and manipulate data in the custom applications you develop. In the next unit, we give you tools to ensure that data is being restricted where appropriate.

Resources

Note

Note

Remember, this module is meant for Salesforce Classic. When you launch your hands-on org, switch to Salesforce Classic to complete this challenge.

retargeting