Skip to main content
Registration for .conf24 is open! Join us June 11-14 in Las Vegas.
 
 
 
Splunk Lantern

New tables queried by a Salesforce cloud peer group

 

A search might show first-time query attempts to sensitive tables by a peer group that has previously not accessed the tables in question. This detection can help prove that individuals within the organization are not abusing or misusing legitimate access to assets that store and process personal data. Because so many people in your organization have access to Salesforce, you want to monitor regularly for new table queries. 

Required data

Salesforce data

Procedure

  1. Populate the lookup_sfdc_usernames lookup provided by the Salesforce Add-on with live values from your site.
  2. Run the following search. You can optimize it by specifying an index and adjusting the time range.
| search QUERY_TABLE="Account*" OR QUERY_TABLE="Contact*" OR QUERY_TABLE="Opportunity*" 
| lookup lookup_sfdc_usernames USER_ID 
| stats earliest(_time) AS earliest latest(_time) AS latest BY Username, QUERY_TABLE
| lookup SFDC_User_Lookup.csv USER_NAME OUTPUT peergroup 
| makemv peergroup delim=","
| multireport [| stats values(*) AS * BY USER_NAME  QUERY_TABLE  ] [| stats values(eval(if(earliest>=relative_time(maxlatest,"-1d@d"),QUERY_TABLE ,null))) AS peertoday values(eval(if(earliest<relative_time(maxlatest,"-1d@d"),QUERY_TABLE ,null))) AS peerpast BY peergroup QUERY_TABLE   ]
| eval user=coalesce(user, peergroup) 
| fields - peergroup 
| stats values(*) AS * BY USER_NAME  QUERY_TABLE
| where isnotnull(earliest)
| eval peergroup_name="SFDC_User_Lookup.csv", isOutlier=case(len(peergroup_name)>0 , if(isnotnull(earliest) AND earliest>=relative_time(maxlatest,"-1d@d") AND isnull(peerpast),1,0), earliest >= relative_time(maxlatest, "-1d@d"), 1, 1=1, 0)

Search explanation

The table provides an explanation of what each part of this search achieves. You can adjust this query based on the specifics of your environment.

Splunk Search Explanation

|search QUERY_TABLE=Account* OR QUERY_TABLE=Contact* OR QUERY_TABLE=Opportunity*

Filter the results to include only queries of sensitive tables (Account, Contact, or Opportunity), or their derivatives. 

|lookup lookup_sfdc_usernames USER_ID

Convert the SFDC USER_ID into a friendly username via a lookup. 

|stats earliest(_time) AS earliest latest(_time) AS latest BY USER_NAME, QUERY_TABLE

Calculate the earliest and the latest time this combination of fields occurred.

| lookup SFDC_User_Lookup.csv USER_NAME OUTPUT peergroup 
| makemv peergroup delim=","
Enrich primary with peer group.
| multireport [| stats values(*) AS * BY USER_NAME  QUERY_TABLE  ] [| stats values(eval(if(earliest>=relative_time(maxlatest,"-1d@d"),QUERY_TABLE ,null))) AS peertoday values(eval(if(earliest<relative_time(maxlatest,"-1d@d"),QUERY_TABLE ,null))) AS peerpast BY peergroup QUERY_TABLE   ] Compare the number of Secondary Fields viewed today and historically by the Primary Field. multireport is a search operator that allows you to leverage the power of stats, but multiple times.
| eval user=coalesce(user, peergroup) 
| fields - peergroup
| stats values(*) AS * BY USER_NAME  QUERY_TABLE
Join the two | stats output together into one, so that you can analyze them together.
| where isnotnull(earliest) Filter out null earliest to handle corner cases and make a clean report.
| eval peergroup_name="SFDC_User_Lookup.csv", isOutlier=case(len(peergroup_name)>0 , if(isnotnull(earliest) AND earliest>=relative_time(maxlatest,"-1d@d") AND isnull(peerpast),1,0), earliest >= relative_time(maxlatest, "-1d@d"), 1, 1=1, 0) If the earliest time you have seen that value was within the last day, that means the first time you've ever seen it just happened, and it qualifies as anomalous.

Next steps

While there are no traditional false positives in this search, there will be a lot of noise. Every time this search runs, it will accurately reflect the first occurrence in the time period you're searching over (or for the lookup cache feature, the first occurrence over whatever time period you built the lookup). You should not review these alerts directly (except for high sensitivity accounts), but instead use them for context or to aggregate risk.

For most environments, these searches can be run once a day, often overnight, without a lag. If you want to run this search more frequently, or if this search is too slow for your environment, leverage a lookup cache. 

When this search returns values, initiate your incident response process and identify the peer group demonstrating this behavior. Capture the time of the event, the user's role, and tables queried. If possible, determine the system used and its location. Contact the user and their manager to determine if the download is authorized, and then document that it was authorized and by whom. If you cannot find authorization, the user credentials may have been used by another party and additional investigation is warranted.

GDPR Relevance: This search can be considered an effective security control, as required by Article 32. This is applicable to processing personal data from the controller and needs to also be addressed if contractors or sub-processors from third countries or international organizations access and transfer personal data (Article 15).

Finally, you might be interested in other processes associated with the Protecting a Salesforce cloud deployment use case.