Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Wednesday, May 20, 2020

Dreamforce 2019 Presentation - Reducing the Cost of Enforcing CRUD and FLS in the ESAPI

At Dreamforce this last year (2019) Chris Peterson and I gave a theater presentation on combining the new Apex Security.stripInaccessible method with the existing ESAPI library for enforcing Create, Retrieve, Update, Delete (CRUD) and field level security (FLS) in Apex.

Unfortunately the Dreamforce theater sessions weren't recorded in 2019 as they were in previous years 🤦‍♂️. To make up for that, below are the session slides. I'll also expand on the key points in this blog post. These will be my words rather than Chris's, although I'll try and cover most of the same content.

What is the ESAPI?

The ES stands for Enterprise Security. And the API... Well, hopefully you know what an API is.

The Salesforce ESAPI is a port of a Java library created by OWASP (Open Web Application Security Project).

To address why you would want it in your Salesforce org, here is a quote from the OWASP ESAPI project page:

The ESAPI libraries are designed to make it easier for programmers to retrofit security into existing applications. The ESAPI libraries also serve as a solid foundation for new development.

These seem like noble goals. We want to improve the security of existing applications and implement newer applications with the same level of security from the start.

The three core areas that the Salesforce ESAPI addresses are:

  1. Input Validation - is a given string a valid date? Is it a valid credit card number? A valid redirection URL?
    • E.g. ESAPI.validator.SFDC_isValidDate
  2. Output Encoding - is is safe to render the content back to the users browser via HTML?
    • E.g. ESAPI.encoder.SFDC_URLENCODE
  3. Access Control - enforce the built in access control mechanisms: CRUD, FLS, and Sharing.
    • insertAsUser/updateAsUser
    • DML on a limited set of fields
    • Override sharing for a single DML operation

(Re) Introducing the ESAPI

Salesforce originally released their version of the ESAPI library in 2010. In 2016 they added the new ESAPI.encoder.SFDC_BASE64_URLENCODE method. Other than that it was stalled for any maintenance or new development.

In 2019 Chris Peterson and Jake Meredith from Salesforce took ownership of the Github repo. Even better, they are accepting pull requests.

One of the first steps in rejuvenating the repo was to increase the built in code coverage from 54% to 93% on the security specific test methods. And, perhaps more importantly, add a number of meaningful assertions and negative test cases along the way. Overall project test coverage is now up by 39%.

One of the particular challenges with this was scripting out of the box test cases using only the built in Profiles and sObjects. The test cases needed to be portable to any org, so they couldn't rely on a specific custom Profile existing. At the time the "Read Only" profile was the most restrictive system profile available. Going forward I might revisit this with the still to GA Minimum Access profile.

With the better test coverage in place it was then possible to overhaul how the field and object level security was enforced. More on that later...

A Recap of the Security.stripInaccessible() method

The Spring '20 release included the GA version of the new Security.stripInaccessible method.

This new method provides a streamlined way to check both field and object level data permissions for the following access types:

  • AccessType.READABLE - Check the fields of an sObject for read access.
  • AccessType.CREATABLE - Check the fields of an sObject for create access.
  • AccessType.UPDATABLE - Check the fields of an sObject for update access.
  • AccessType.UPSERTABLE - Check the fields of an sObject for insert and update access.

The SObjectAccessDecision Object

After calling stringInaccessible() an SObjectAccessDecision object is returned. This provides a number of helpful methods.

getRecords() provides a new List<SObject> that has all the inaccessible fields removed. These are also detached from the source sObjects.

Two additional methods getModifiedIndexes() and getRemovedFields() provide details about which records and specific fields were modified.

How it works in practice to enforce security requirements

Using the newer stringInaccessible method has a number of advantages. It will cover all possible sObject field types. It will check relationship fields, including nested relationships. Sub-queries and polymorphic lookups are also covered.

The example in the image above shows a new Opportunity for "Appy's App" that was generated in the trusted system mode. As such, it could set the custom Standing__c and Value__c fields. This Opportunity is then passed through stringInaccessible with the AccessType.CREATABLE parameter. This does all the hard work for us of checking the users Profiles, Permission Sets, the Permission Set groups, the muting permission sets, etc... The output Opportunity has the fields that the user doesn't have create access to completely removed. The stripped fields aren't null: they're really undefined. This is important when it comes to subsequent DML as we don't want to inadvertently clear fields out.

Other advantages:

  • It's particularly useful when handling untrusted input (like from JavaScript controllers)
  • It's also great for gracefully degrading UI experiences like SFDC does natively

Example walk through code the changes to the ESAPI

The video shows the core structural changes that were made to the ESAPI methods to use the new methods.

Measuring the Performance changes - Methodology

Beyond enforcing the security requirements the next important consideration is changes to CPU Limit usage and Heap usage. Usually you trade more CPU for less Heap or vice versa. If we can cut both down we are doing well!

The general goal is always to see equal of better performance while enforcing the same security requirements. There may be some tradeoffs in performance made, but the security can't be compromised on. The coverage and assertions from the automated tests ensure we are still enforcing the same security requirements.

The performance differences in terms of Apex limits were measured using Test harness classes and Adrian Larsons LimitsProfiler framework. Performing multiple runs between the current/baseline implementation and the new version using the stripping methods allows the relative changes in limits to be measured.

During the testing it was important to have the debug logging completely off as it would otherwise affect the outcomes.

The testing below was done in ALL_OR_NONE mode. This is more demanding than the alternative BEST_EFFORT mode as it requires per field level checks.

To allow for the limits testing framework to repeatedly insert multiple records Savepoints were used as part of the setup and teardown steps. This prevented hitting the storage limits while still measuring the performance differences in the ESAPI.

Measured results for bulk inserting Contacts

The performance difference can vary greatly based on scenario:

  • There is negligible performance difference when checking object CRUD permissions. Note, the Apex ESAPI is still enforcing against the sObject Schema.SObjectType until 224 (Spring `20) with the fix.
  • There is a significant performance difference if there are a large number of requested fields that aren’t set on all the sObjects.

Measured improvements on 25 iterations inserting 200 Contacts. 33 Standard fields

  • 25% Less CPU usage
  • 18.6% Less Heap usage

Links and Resource

Tuesday, January 10, 2017

JavaScript Security for Visualforce

I thought I'd touch on some of the security considerations that should be made when working with JavaScript from Visualforce.

Cross Site Scripting (XSS)

The risk of cross site scripting is always something to be aware of when developing web applications and needs to be considered when using JavaScript in Visualforce as well. Generally speaking, you want to prevent untrusted user input from being reflected back into JavaScript code.

As an example - say you were trying to read a page parameter info JavaScript with the following (Example only - DON'T DO THIS):

<apex:page>
    <script>var foo = '{!$CurrentPage.parameters.userparam}';</script>
</apex:page>

If you load this in the browser and include a &userParam=bar in the query string then the resulting HTML is:

Great! But what if someone puts something malicious into the URL? Something like 1';alert('All%20your%20Salesforce%20are%20belong%20to%20us');var%20foo='2. Here is the result in the browser:

And again from the page source:

So definitely not what we wanted. Notice how the apostrophe characters in the user input allow the code to take on an entirely different meaning. It would be very easy to extend the example to submit the current session cookies to an external resource - compromising you Session Id and pretty much everything else from there.

The solution here is to use JSENCODE to encode any text before reflection into JavaScript. This will use a backslash to escape any unsafe JavaScript characters, such as apostrophe (').

<apex:page>
    <script>var foo = '{!JSENCODE($CurrentPage.parameters.userparam)}';</script>
</apex:page>

See also:

Javascript Remoting with escape: false

When using Javascript Remoting beware the using {escape:false} in the configuration and loading the result into the DOM. Much like the basic XSS example above, it can be used to inject executing JavaScript into the page.

See also:

Avoid the urge to hack the Salesforce DOM

Not so long ago developers would put JavaScript in the sidebar so it would load with every page. This could then be used to manipulate the standard Salesforce DOM to do all sorts of things, such as showing/hiding components, adding additional validation, or changing their presentation.

Salesforce took umbrage with this approach as it opened up all sorts of consistency and security problems. As such, they shut the practice down in the Summer '15 release. Needless to say, those who had used the sidebar to manipulate the page found their workaround hack solution no longer working. Best to avoid these sorts of unsupported shenanigans if you can as they will be closed off sooner or later.

See also:

Protect the Session Id / AccessToken

The Session ID is the key to the kingdom. If someone can get hold of yours they can interact with Salesforce like you would*. If you can avoid exposing it in Visualforce then do so. E.g. Use JavaScript Remoting rather than interacting with the APIs directly.

Depending on the context where you request it, you can get a "second class session id" that doesn't grant you the same level of access as a full "first class" UI session type.

For instance, a Session ID in Visualforce from can be used to make API calls, but can't be used to access the full web UI (Such as via frontdoor.jsp).

Checking the User Session Information page can show the different Session Types that get created. In the example below note the TempVisualforceExchange Session that was created from the Parent UI Session.

See also:

* There are some exceptions on if they can use it if "Lock sessions to the IP address from which they originated" or "Enforce login IP ranges on every request" are enabled.

Static Resource rather than CDN

Using a CDN such as Google Hosted Libraries or the Microsoft Ajax Content Delivery Network to bring in something like jQuery is appealing, but can open you up to security problems and overall make the app exchange security review more troublesome than it needs to be. Instead consider using a zip file in a static resource and referencing the contents of the zip using URLFOR.

See also:


Further reading:

Tuesday, November 4, 2014

Salesforce integration failures due to disabled SSL 3.0 (POODLE)

In response to the published security vulnerability on SSL 3.0 encryption (POODLE) Salesforce has put out the Knowledge Article Salesforce disabling SSL 3.0 encryption.

One important section with regards to web services that are called by Salesforce: (my emphasis)

Additionally, Salesforce recommends customers disable SSL 3.0 encryption in their own IT environment as soon as possible, unless they use call-out integrations. If a customer uses call-out integrations, and they have not already disabled SSL 3.0 in their own environment, then Salesforce recommends that they wait until after Salesforce has disabled SSL 3.0 for outbound requests.

The current timeline for outbound requests dropping support for SSL 3.0 is the 3rd of December 2014 for sandboxes and the 10th of December 2014 for production orgs.

If you work with a web service that disables SSL 3.0 before then you can start seeing exceptions like:

System.CalloutException
Message:  IO Exception: Remote host closed connection during handshake

I've also seen it reported manifesting in Batch Apex as:

Received fatal alert: handshake_failure

This can occur even if the web service supports TLS1.0 or higher.

Quotes attributed to support:

"We will use TLS with callouts but if it fails. We drop down to SSL and hard code to send it via SSLv3 for 24 hours or an app restart. Which ever comes first. This should address any changes that occur with the way other companies integrate with Salesforce until we completely disable SSL 3.0 on December 10th." Source
"I am from Salesforce Developer Support Team. I have taken ownership of your case regarding POODLE vulnerability. At present some outbound calls are initiated using SSLv3 ClientHello, so if this is disabled on your server, there'll be a handshake failure. Until then, it is advised that you support this for incoming calls (received from Salesforce). At present R&D and our Tech Ops organization are aggressively working on a strategy around this. Once this is finalized, there will be a tech comm broadcast as expected."
"The R&D team shall be releasing this on 11/4/2014. After that you may turn off SSLv3 without running into the handshake failures"
Source

This presents a bit of an immediate problem. Salesforce is trying to fallback to SSL 3.0 on services that only support versions of TLS. At this stage, if you don't have control of the web service or the ability to get it to accept SSL 3.0 again until mid December the only option might be to wrap it in a proxy service that does support SSL 3.0 encryption.

Another fun part of the change is that Inbound SSL 3.0 support will start phasing out from the 7th of November. Between then and the 10th of December there will be cases where Salesforce servers won't be able to call Salesforce hosted web services. At least some of the time anyway when they aren't successfully using TLS.


Update 6/11/2014: Indications are that Salesforce have been silently updating servers to prevent the fallback to SSLv3 if the target server doesn't support it. It's hard to confirm what is going on as there isn't an official known issue that can be linked to.


Update 7/11/2014: Salesforce support responded to some of the outstanding issues:

All I see you guys have various questions and I think I can answer quite a few of them, I manage part of the technical support security team at salesforce. Email me at bestebez@salesforce.com (you can look at my linkedin profile if you question who i am).

Questions that have been raised around Salesforce’s support of SSL 3.0 and TLS 1.0. While we are in the process of disabling SSL 3.0, Salesforce currently supports TLS 1.0 and TLS 1.2 for inbound requests and TLS 1.0 for outbound call-outs.
Our Technology Team has been actively working to address an issue that causes outbound call-outs to use SSL 3.0 more frequently than they should, given we have TLS 1.0 enabled. We understand that this may have caused issues for customers who have already disabled SSL 3.0 in their call-out endpoints. We released a fix to Sandboxes last Friday, October 31, and plan to release the fix to production instances during off-peak hours on Wednesday, November 5, 2014.
Many customers and partners who have tested this fix in their Sandboxes have reported successful connections using TLS 1.0. A few customers continued to experience TLS 1.0 issues on their Sandboxes, and our Technology team is working with them to find a solution.

There was an issue specifically to Na14 that was generating more outbound messages that were using SSLv3 but that has since been fixed. That is probably why a few of you guys saw an issue with.
Source

See Also:

Wednesday, August 7, 2013

Checking the FormsAuthentication cookie size is within 4096 bytes

I recently encountered an issue with the FormsAuthentication cookie not being set for certain users.

It turns out the cause was the total cookie size exceeding 4096 bytes and the browser not accepting it.

Aside from fixing the root cause and as a preventative measure for the future, I've added something like the following to detect the excessive cookie size. Note that this is a bit approximate as it doesn't take into account the cookie name, expiry date, etc...

    FormsAuthenticationTicket ticket = // Separate code to setup the authentication, including the UserData

    string hash = FormsAuthentication.Encrypt(ticket);
    int maxByteSize = 4000; // Max Cookie Size is 4096 including Cookie Name, Expiry, etc...
    if (System.Text.ASCIIEncoding.ASCII.GetByteCount(hash) > maxByteSize) 
    {
        // Raise the alarm that the cookie is going to get rejected by the browser
    }
    
    // Continue with standard cookie setup...
    HttpCookie formsAuthCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);

Wednesday, January 23, 2013

Using the Burp Suite to test a Web Service that is consumed in a Salesforce app

The following steps can be used to run the Burp Suite scanner against a Web service that is consumed in a Salesforce app via callouts.

The basic idea is to:

  1. import the Web Service WSDL into SOAP UI,
  2. configure SOAP UI to use the Burp Proxy,
  3. use SOAP UI to simulate the SOAP requests for typical use cases, This will require updating the sample requests generated in SOAP UI to represent those made from Salesforce under normal usage.
  4. select the requests to scan from the Burp Target, Site map tabs

Get a Burp Suite License

ISV partners can submit a Burp License Request.

Install and run Burp

I put the Burp jar file and license txt file in a directory and started it with the following in a batch file:

java -jar -Xmx1024m burpsuite_pro_v1.5.04.jar

See Also: Getting Started With Burp Suite

Configure Burp

Turn “Intercept” (Proxy->Intercept) off within Burp.

Configure SOAP UI to use the Burp Proxy

File > Preferences > Proxy Settings:

127.0.0.1:8080
You can find the Burp Proxy details Under Proxy > Options > Proxy Listeners

You may need to installed Burp's generated CA Certificate into the Trusted Root Certification Authorities tab if using SSL. See Installing Burp's CA Certificate. If not configured you get the following error message in Soap UI "Error getting response; javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated."

For SoapUI to pickup the new cert:

  1. Go to the path: C:\Program Files (x86)\SmartBear\SoapUI-5.0.0\jre\lib\security
  2. Export the Burp CA Certificate using Proxy > Options > CA certificate... > Export: Certificate in DER format.
  3. Use the Java keytool executable to import the certificate:
    "C:\Program Files (x86)\Java\jdk1.7.0_67\bin\keytool.exe" -import -alias burp -file "C:\WhereYouExportedTheDerCertificate\PortSwiggerCA.cer" -keystore cacerts
  4. The keystore password will be:
    changeit

Use SOAP UI to simulate the web requests that Salesforce would make to the web service

This will require you to update the sample requests that SOAP UI generates for each of the web methods with realistic request data. Try to mimic the calls that Salesforce will be making.

When the SOAP UI requests are submitted Burp will record them under the Target > Site map tab.

Start the Burp Scanner

Under the Target > Site map tab select the request nodes or host/branch that you want to scan. If it was a website you would usually do an "Spider this branch" at this point. Start the Scanner for the branches by selecting "Actively scan this branch".

Under the Scanner > Scan Queue tab the requests will appear and be processed. The output will start appearing under the Scanner > Results tab.

Export the Burp Scanner Results

Under the Scanner > Scan Queue tab select the results of interest then right click and select "Report selected issues"

The Printer-friendly version with hyperlinks works well for both screen reading and printing. Defaults can be used for the remaining steps. Ensure you save the report in a file with the ".html" extension.


See Also:

Friday, May 6, 2011

Location of Sitecore data folder and App_Data

Sitecore recommends moving the data folder outside of the webroot because of security issues. This is normally a good idea, as the datafolder contains information, which shouldn’t be accessible for end users. However you might as well use .NET’s security applied to the App_data folder.
Jens Mikkelsen: Consider using the App_data folder as your Sitecore data folder

Monday, August 30, 2010

SEC302 Hack-Ed II: Stop the hacking

Presenters: Andy Prow, Kirk Jackson

Tech.Ed Online

oWasp.org

Enumerating usernames - finding valid users

Leaking content out to Facebook

Threat modelling

Counter-measures

Text file with HTML in IE can run as HTML.
X-Content-Type-Options nosniff
Don't sniff any HTML content out of files.

Serve content via a handler rather than the web servers file system. E.g. They could upload a ASPX file to the upload folder and potentially run it.
Omit Content-Disposition: attachment; filename=%lt;file>

Tab Nabbing
- Change the Title
- Change the favicon
- Load the target site over the top of harvesting site.

Thursday, March 18, 2010

Secure ASP.NET Session Cookies

How to check for insecure cookies

Install the Firecookie extension for Firebug so you can examine the cookie security settings.

Before

Set requireSSL to true.

  <system.web>
    <!-- ... -->
    <httpCookies requireSSL="true"/>
    <!-- ... -->
    <authentication mode="Forms">
      <forms name=".ASPXAUTH"
      loginUrl="~/Login.aspx"
      defaultUrl="~/Default.aspx"
      protection="All"
      timeout="30"
      path="/"
      requireSSL="true"
      slidingExpiration="true"
      cookieless="UseCookies"
      enableCrossAppRedirects="false" />
    </authentication>
    <!-- ... -->
  </system.web>

After

See Also: