5

I was looking at Salesforce's documentation for implementing an OAuth callback and I noticed they are accepting a "sfdc_community_url" from the client, which should normally only ever be a Salesforce hosted server. But as an attacker, I can give the callback URL any domain I want, including my own attack server.

If the service provider's application is relying on my attack server to validate the code, then my server can respond with a gibberish access_token and a token ID that also points back to my attack server. Then my attack server can send any JSON it wants in the follow up request for identity information. If I can spoof any identity information, I can provide any email or username and the service provider would then authenticate me as that user.

Granted, the Salesforce gibberish token is worthless, but if the service provider is using Salesforce mainly as just an identity provider, the token isn't used for much anyway and I've still signed in as someone I shouldn't have.

Is this scenario possible? I don't see any technical issues as long as you know the email or username of the person you want to sign in as.

Their possibly vulnerable section of sample code is below. The full sample code is at: https://help.salesforce.com/s/articleView?id=sf.external_identity_login_server_callback.htm&type=5

        String tokenResponse = null;
        String communityUrl = null;
        HttpClient httpclient = new HttpClient();
        try {            
            // community_url parameter passed from redirect uri.
            communityUrl = request.getParameter("sfdc_community_url");
            // Token endpoint : communityUrl + "/services/oauth2/token";
            PostMethod post = new PostMethod(communityUrl+"/services/oauth2/token");
            post.addParameter("code",code);
            post.addParameter("grant_type","authorization_code");
            // Consumer key of the Connected App.
            post.addParameter("client_id", CLIENT_ID);
            // Consumer Secret of the Connected App.
            post.addParameter("client_secret",CLIENT_SECRET);
            
            // Callback URL of the Connected App.
            post.addParameter("redirect_uri", 
                "https://boiling-brushlands-41143.herokuapp.com/_callback");
            
            httpclient.executeMethod(post);
            tokenResponse = post.getResponseBodyAsString();
            post.releaseConnection();
 
            System.err.println("tokenResponse: " + tokenResponse);
        } catch (Exception e) {
                throw new ServletException(e);
        }


        JSONObject identityJSON = null;
        try {
            JSONObject token = new JSONObject(tokenResponse);
            // get the access token from the response
            String accessToken = token.getString("access_token");
            String identity = token.getString("id");
            httpclient = new HttpClient();
            GetMethod get = new GetMethod(identity + "?version=latest");
            get.setFollowRedirects(true);
            get.addRequestHeader("Authorization", "Bearer " + accessToken);
            
            // get identity information using the access token
            httpclient.executeMethod(get);
            String identityResponse = get.getResponseBodyAsString();
            get.releaseConnection();
            identityJSON = new JSONObject(identityResponse);
            identityJSON.put("access_token", accessToken);
        } catch (Exception e) {
            throw new ServletException(e);
        }
4
  • 3
    This chunk of code is an outdated example of how to implement this. Reading of sfdc_community_url from the request is not good, using a client secret and not using PKCE in an authorization code grant flow is a much more serious error. We let the right SF folks know about this, hopefully it'll get fixed.
    – identigral
    Sep 29, 2021 at 16:18
  • @identigral I really appreciate your letting them know. Thanks! Sep 29, 2021 at 17:10
  • 2
    Hi, I'm the PM for identity at Salesforce. Identigral pointed me to this post (thanks @identigral). We've filed a doc bug to address it. Thanks everyone for making our product better. Oct 7, 2021 at 17:27
  • 1
    @DavidBrossard Just wanted to flag that the documentation still has the vulnerability. Your customers are likely using it to create their proof-of-concepts and creating security vulnerabilities in their service provider applications Apr 20, 2022 at 14:18

1 Answer 1

1

This code should not be used to authenticate a user with the web server, only to enable API access to the specified community. In that context, your proposed attack won't allow any access, as the access token is only "valid" for the attack server.

It's always important to make sure that you understand the context for the type of code you're writing. If you were to accidentally/mistakenly use this code to authenticate to your own service, using Salesforce as an Identity Provider, this attack would certainly allow you to spoof a user session and gain whatever access the user has. It would not allow any access to Salesforce data, however.

The larger concern is that this code allows you to extract a client id and client secret, which would allow you to then impersonate the app they're trying to use. You could use this to list a similar app on a storefront, or use DNS poisoning, misspelled DNS names, etc, in order to try to catch people unaware and do nefarious things with their community user, such as posting fake content or stealing data.

3
  • 1
    Well, Salesforce is an identity provider and service providers likely use it as such, and likely use this code in their implementation, or at least as a starting point for the general process. Would you think this is a serious concern that Salesforce should do something about? Sep 29, 2021 at 15:30
  • 1
    @KevinDenham Perhaps the docs could clarify, I guess. Salesforce is both an Identity Provider (IdP) and Service Provider (SP). This code sample is, to me, clearly meant to place Salesforce in a SP role, not an IdP role. For IdP, you probably want Salesforce Identity, which provides SAML assertions. Of course, it's possible to do SAML wrong, too, but much harder, as it's designed to thwart those kinds of attacks (e.g. needing a private key to sign assertions).
    – sfdcfox
    Sep 29, 2021 at 15:43
  • @KevinDenham Or, stated differently, if a web app is using Salesforce as an SP, it needs the token, and therefore isn't vulnerable to a fake server. If the web app does not need the token, then Salesforce is an IdP role and shouldn't be providing a token, only an identity assertion of some sort. OTOH, I do still see your point, perhaps the app is using the identity of the user to connect to an account of their own. In this case, the web app should connect only by Salesforce Org Id and User Id, not by email or any other easily guessable information.
    – sfdcfox
    Sep 29, 2021 at 15:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .