5

I'm working on a managed package where a requirement, out of our hands, is to authenticate to a SOAP API via WS-Security. I was hoping we'd take the strategy of using Named Credentials. This would require us to use merge fields (as documented here https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_named_credentials_merge_fields.htm). Since the WS-Security XML header is in the HTTP request body, the named credential needs to have the "Allow Merge Fields in HTTP Body" option ticked.

It's occurred to me though, there could be a security risk here. These API calls will contain data mapped by an administrator to send from records in their org. If user were to include the text {!$Credential.Password} somewhere in a text field of a record, oops, now that password would be substituted somewhere it shouldn't be.

Would it be wisest to sanitize the rest of the request body to avoid this? Any user data would definitely come after the XML header so I could, for example, check if xmlString.countMatches('$Credential') > 2. And if so, either throw an error or replace it with something safe.

And for that matter, would it be a Security Review concern if our package will only work when the Named Credential "Allow Merge Fields in HTTP Body" is ticked?

0

I don't know if it's "best", and I can't speak for the security review process, but if I were in your shoes, I would escape all merge syntax entirely. It's hard to see a valid reason to support it.

Below is a simple example of what I would do, posted as an anonymous script.

public static String escapeMergeSyntax(String input)
{
    return input == null ? input : input.replaceAll('\\{!(.+?)\\}', '[$1]');
}

String body = 'Some content {!Credential.Password} and other {!mergeFields}';
// assume body is untrusted subscriber input

body = escapeMergeSyntax(body);
// now the subscribe input should be unable to expose your credentials

system.debug(body);

One note about regular expressions, you need to set the single-line flag or users can inject whitespace to work around your escaping. I'm not certain, but I think the compiler would just ignore these newline characters and proceed with merging in the sensitive data. Try this input with and without the flag set:

public static String escapeMergeSyntax(String input)
{
    return input == null ? input : input.replaceAll('(?s)\\{!(.+?)\\}', '[$1]');
}

String body = 'Some content {!\nCredential.Password\n} and other {!mergeFields}';
//                            ^^ clever users may try to inject whitespace

body = escapeMergeSyntax(body);
// setting the (?s) single-line flag will make sure dot matches newline

system.debug(body);
  • I can't escape the entire body, because the username and password merge fields still legitimately need to go inside the XML header, which is part of the request body. The only time I'm transforming the XML nodes into a string is right at the end when the whole XmlDocument is ready. So either I use an escaping function on every single individual text node that derives from user input, or I apply one function to the final XML string that green-lights my intentional merge fields and escapes all the others. – Charles T Feb 19 '18 at 3:52
  • @CharlesT It seems to me like it might be simpler to just escape all of those text nodes, but that's hard to say from the outside. – Adrian Larson Feb 19 '18 at 3:54
  • Fair point. As for merge syntax, AFAIK the ONLY merges it allows in the body are ones including $Credential so searching for just that string should be what brings up the red flags. What I don't know is the behaviour for other attempts at merge fields - will have to test this out. – Charles T Feb 19 '18 at 5:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.