Start tracking your progress
Trailhead Home
Trailhead Home

Prevent Open Redirects in Your Code

Learning Objectives

After completing this unit, you'll be able to:
  • List three mitigation strategies to prevent open redirection.
  • Implement a whitelist-based approach to prevent open redirect.
  • Block open redirect attacks by forcing local redirects.

Strategies for Mitigating Open Redirect

Back in the Kingdom Management developer org, you have a component of your application that leverages local redirects to move users throughout different app components. But as we’ve learned from the previous units, to move users safely, you’ll need to add layers of defense to your application.

There are three main strategies to prevent open redirect attacks:

  1. Hardcode all redirects.
  2. Force only local redirects.
  3. Whitelist redirects.

Hardcode Redirects

The first strategy for preventing open redirect is to leverage hardcoded redirects. Rather than exposing your redirection parameters to a user (or potential attacker), in a hardcoded redirect you set the value explicitly as in the following example.

Apex:

savePage = new PageReference(‘/home/home.jsp’);
savePage.setRedirect(true);
return savePage;

However, this approach doesn’t lend itself to flexible applications, which dynamically change based on user actions. Therefore this approach won’t work for every developer use case.

Force Local Redirects Only

The next defense option is to force all redirects to go only to resources in the local domain (for example, the Salesforce instance that your application runs on). The core concept of this mitigation strategy is that the local domain is under your control and therefore safer than the broader Internet, so you limit the scope of potential redirects. This is the code equivalent of pulling up your drawbridge, only allowing transportation within the castle walls.

To understand how this works, let’s explore it in more detail in the Kingdom Management developer org.

  1. Log in to the Kingdom Management developer org and navigate to the Open Redirect app.
  2. Click the Relative URL Protection Demo tab.

    In this app, users assign castle workers to perform duties in different areas of the castle. When the user clicks Save or Cancel, they’re redirected back to the main page. However, this application is vulnerable to open redirect because the URL parameters saveURL and cancelURL can be modified by an attacker to redirect a user to an external site of their choosing. So let’s modify our Apex to ensure only local redirects are possible.

  3. Click the Apex link at the bottom of the page to navigate to the controller for this application.
  4. Update the save() function, updating your apex code match the code below, forcing all URLs to be relative URLs.

    Apex:

    public PageReference save(){
        PageReference savePage;
        if (Schema.SObjectType.Personnel__c.isUpdateable()){
        try{
            update unassigned;
            String completion = ApexPages.currentPage().getParameters().get('onSave');
    
            if(completion.startsWith('/')){
                ​completion=completion.replaceFirst('/','');
            }
            savePage = new PageReference('/'+completion);
    
            savePage.setRedirect(true);
            return savePage;
        [...]
    
  5. Reload the Visualforce page and enter any external URL like https://www.google.com as the value for retURL. You should see an error message appear.
  6. Click Save. You should see an error message appear.

To understand how this works, let’s break down the code that you added. When the user clicks Save, it calls the save function in Apex which reads in the value of retURL from the URL.

String completion = ApexPages.currentPage().getParameters().get('onSave');

Next, the code checks if the string starts with a forward slash.

if(completion.startsWith('/')){

If it does, it removes the first forward slash, plus all subsequent forward slashes (the additional plus sign represents all repeated instances of the preceding character).

completion.replaceFirst('/+','');

Then the URL is prepended with a single forward slash.

savePage = new PageReference('/'+completion);

This single forward slash makes sure that every URL is local to Salesforce. So, for example, when you enter www.google.com for onSave and save, the redirect becomes https://c.[yourinstance].visual.force.com/www.google.com, which doesn’t exist. This results in an error message, successfully preventing redirects to external sites.

You might be wondering why the code bothers to remove slashes if we want to start with a slash anyways. There is a tricky game attackers will try with redirect functionality. The URL /www.google.com will be a local redirect. The URL //www.google.com is treated by many browsers as a valid external redirect. An attacker could submit /www.google.com as a URL, and code that only adds a forward slash might unwittingly enable an external redirect.

The double slash redirect does not work in Visualforce at this time, so to demo this we have included the onCancel URL parameter and a Cancel button, which uses a JavaScript-based redirect rather than the Apex PageReference() method.

<a href="/{!$CurrentPage.Parameters.onCancel}" id="cancelbutton">

You can try this double slash trick here. Change the value of the onCancel URL to something like /www.google.com and hit Cancel to observe the effect.

Whitelist Redirects Only to Known External Domains

While the relative URL defense prevents open redirect attacks, it’s not appropriate for all developer use cases. Using forced relative URLs can be like pulling up a drawbridge. But what if you can’t isolate your castle from the outside world? What if you need supplies from neighboring towns? How do you get them securely?

The idea here is to utilize a whitelisting approach where the developer maintains a list of acceptable locations for URL redirection, which should include only acceptable and safe external domains. Whenever a redirect is performed, the domain of that redirect is compared against the domains in the whitelist. If there is a match, the redirect is performed. If not, the request returns an error. Think of it as having additional guard at the gate of your castle, checking the source of where all the incoming and outgoing goods are traveling.

In fact you may recall from the previous unit that this is the exact method that Salesforce uses on our standard pages only allowing redirection targets like *.visual.force.com, *.salesforce.com, *.content.force.com.

Let’s give this protection method a try in your Kingdom Management developer org.

  1. Log in to the Kingdom Management developer org and navigate to the Open Redirect app.
  2. Click the URL Validation Protection Demo tab.
  3. Click the Apex link at the bottom of the page to navigate to the controller for this application.
  4. Update the save() function, updating your apex code match the code below, to only allow redirects to certain domains.

    Apex:

    public PageReference save(){
        PageReference savePage;
        if (Schema.SObjectType.Requisition__c.isUpdateable()){
        try{
            update requisitions;
            String onsave = ApexPages.currentPage().getParameters().get('onSave');
                            
            URL currentURL = New URL('https://' + ApexPages.currentPage().getUrl());
            Set<String> whiteListedDomains = new Set<String>();
            whiteListedDomains.add(currentURL.getHost());
            whiteListedDomains.add('www.salesforce.com');
            whiteLIstedDomains.add('www.google.com');
    
            if( onsave == NULL || !whiteListedDomains.contains(New URL(onsave).getHost())){
                onsave = '/home/home.jsp';
            }
    
            savePage = new PageReference(onsave);
            savePage.setRedirect(true);
            return savePage;
    
    [...]
    

    In the modified code, you’re now constructing a whitelist of acceptable redirect domains like www.salesforce.com, www.google.com. Then when the application parses the value of onSave, it checks to see if the supplied URL is within one of those domains. If it is, it performs the redirect; otherwise, it redirects the user to the home page.

  5. To try out the new code, Save and refresh your Visualforce page.
  6. Click Save. You should see an error message appear.

Resources

Open Web Application Security Project (OWASP) - Open Redirect

Open Web Application Security Project (OWASP) - Open Redirect Cheat Sheet

Flower icon used to indicate that the content is for Salesforce Classic

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

retargeting