Request for Comments: API Best Practices

by Moderator Moderator ‎01-29-2016 10:42 AM - edited ‎05-03-2016 10:46 AM (23,260 Views)

Updated 5/3/2016.

 

As payment industry standards evolve, Authorize.Net has seen a need to advise developers on best practices for API usage.

The below is the current draft of our current API Best Practices, which are based on current security best practices and PCI DSS requirements.

 

This is a living document, and will be updated as industry standards and practices evolve. 

Your feedback is appreciated. Please share your feedback in this comment thread.

Thanks!

Note: The key words “must,” “must not,” “required,” “shall,” “shall not,” “should,” “should not,” “recommended,” “may,” and “optional” in this document are to be interpreted as described in the Internet Engineering Task Force standard, RFC 2119: https://www.ietf.org/rfc/rfc2119.txt


Also, by “solution” we refer to the software which handles your payment processing, and its dependencies. This includes but is not limited to the server OSs, software frameworks, and scripting languages used by the solution.


1) Whenever possible, you should use the strongest version of TLS available—as of this writing, TLS 1.2.

PCI DSS 3.1 prohibits the use of early TLS for payment processing. While PCI DSS 3.1 has a grandfather clause giving a deadline of June 2018 for full compliance of legacy systems, new systems are expected to fully support TLS 1.2, and to have early TLS disabled.

If your solution does not currently support TLS 1.2, upgrades to support TLS 1.2 should be made as soon as feasible.

The following operating systems, components, and frameworks are known to support TLS 1.2:

Windows Server

Version 2008 R2 and later. (Source) Windows Server 2008 R2 does not enable TLS 1.2 by default. For instructions on enabling TLS 1.2, see https://technet.microsoft.com/en-us/library/dn786418.aspx.

.NET

Version 4.5 and later. Requires Windows Server 2008 R2 SP1. (Source 1Source 2)

OpenSSL

Version 1.0.1 and later. (Source)

cURL

Version 7.34.0 and later. (Source)

PHP

Version 5.6 and later. Requires OpenSSL 1.0.1 and later. (Source)

Java

JRE 1.7 / JDK 7 and later. (Source) JRE 1.7 / JDK 7 default to TLS 1.0 but can be reconfigured to favor TLS 1.2. In JRE 1.8 / JDK 8, TLS 1.2 is the default configuration. See https://blogs.oracle.com/java-platform-group/entry/diagnosing_tls_ssl_and_https for details.

ColdFusion:

Version 10 with JRE 1.8; Version 11 with JRE 1.7 or greater. (Source)

Perl:

Depends on implementation. Net::SSLeay requires OpenSSL 1.0.1 and later. (Source)

Nginx:

Version 0.7.65/0.8.19 and later. Requires OpenSSL 1.0.1 and later. (Source 1Source 2)

MacOS:

Version 10.9 AKA Mavericks. (Source)

iOS:

Version 5 and later. (Source)

Android OS:

Version 4.2 and later. Requires OpenSSL 1.0.1 and later (bundled by default). (Source)


For more details on this best practice please review the PCI Security Standards Council
Bulletin on Migrating from SSL and Early TLS.


2) Your solution should prefer and prioritize high-security ciphers.

We strongly recommend that your TLS usage have three components: Symmetric encryption algorithm, key exchange, and keyed-hash message authentication.

These are our cipher priority recommendations:

  • ECDHE + AESGCM ciphers should always be selected first. These are TLS 1.2 ciphers.
  • Perfect Forward Secrecy (PFS) cipher suites are preferred with ECDHE. DHE is not preferred.
  • For authentication, ECDSA is preferred over RSA.
  • Keyed hash functions must be used with either SHA-2 or SHA-3. SHA-1 is not allowed
  • AES-128 is preferred to AES-256 for encryption.
  • Authenticated encryption modes (AES GCM, ChaCha20-Polu 1305) modes should be preferred first over other AES modes (e.g. AES-CBC).
TIP: Your platform will ship a list of ordered ciphers and you can use a site such as https://www.howsmyssl.com/ to connect and validate your cipher list. For example, in Ruby this simple program will print out your Ruby cipher list.

 

require "net/https"
require "uri"
require "json"

uri = URI.parse("https://www.howsmyssl.com/a/check")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
resp = JSON.parse(http.request(Net::HTTP::Get.new(uri.request_uri)).body)
puts JSON.pretty_generate(resp)

3) Your solution must be actively supported, with regular security updates, by its original vendor.

Unsupported components or software often lack support for TLS 1.2 and preferred ciphers, and won’t support newer, more secure protocols and ciphers as they are introduced. Furthermore, the lack of support means mitigating new security issues will be much more difficult.

Note that PCI DSS Requirement 6.2 mandates regular security updates for all system components and software, and that critical security patches be installed within one month of release. If the vendor of a component or software no longer provides updates, that component or software might be flagged as out of compliance by Approved Scanning Vendors.

Make sure your platform components are the latest version you can run, and that they include all security patches. Note that you may need to make code changes to enable security features of the new security patches. For example, in .NET 4.5, TLS 1.2 is available by default, but it needs to be referenced in your code. Upgrading to .NET 4.5, and adding “SecurityProtocolType.Tls12” to the System.Net.ServicePointManager.SecurityProtocol property, should provide your solution with support for TLS 1.2. Please consult your platform and framework documentation for more details. 

The PCI Security Standards Council provides a document, “
The Prioritized Approach to Pursue PCI DSS Compliance,” which includes details on how to enforce PCI DSS Requirement 6.2.

PCI FAQ 1130, “Are operating systems that are no longer supported by the vendor non-compliant with the PCI DSS?” focuses on operating system support.


4) If your production environment handles payment data, you must use a network demilitarized zone (DMZ) with firewalls allowing connections only between the DMZ and the production environment.

Your DMZ should allow connections from it to any outside Internet connection, but should limit inbound connections to those necessary for your business.

Authorize.Net is moving their network front-end to allow multiple connection sites worldwide, which will require dynamic IP addressing. Therefore a whitelist of IP addresses will not be possible.

Nonetheless, a firewall whitelist is not sufficient security, especially if you handle payment data, and PCI DSS requires the use of a DMZ to insulate the network handling payment data from the rest of the Internet.

For more details please read the document, “PCI Card Production – Logical Security Requirements.”


5) If your solution doesn’t have built-in HTTP header parsing logic, you should follow RFC 7230, section 2.1.

The RFC explains that the HTTP header block is terminated by “an empty line (i.e., a line with nothing preceding the CRLF) indicating the end of the header fields,” which precedes the HTTP message-body.

Authorize.Net reserves the right to add, remove, or modify HTTP headers as we make changes to our platform. Therefore, we caution against counting HTTP header lines as a means to determine the start of the HTTP message body.

Note that most modern scripting languages and development environments have calls which automatically differentiate between the HTTP headers and HTTP body, and using these calls will remove the need to manually search for the empty line that separates the header and body.


6) Do not hard-code your parsing/serialization logic.

 

That is, do not design your code so that it presumes it knows all API elements and that they will be sent in a particular order.

We add new API features on a regular basis, and if your code presumes there will be no API changes, it will not be able to recover when there are changes made.

Specifically, you must not count HTTP header lines to determine where the API response begins, as HTTP headers are subject to change without prior notice.

Also, your solution should validate against any XSD or WSDL we publish for the API you use. Cached copies of the XSD or WSDL should be refreshed regularly. The HTTP header, Last-Modified, may be used to check for XSD/WSDL updates.


7) When the API returns an error, display or capture both the Error Code and the Error Text.

The Error Code helps to identify the precise error, while the Error Text helps to explain the error in human-readable form. Both pieces of information are invaluable for troubleshooting.

If you choose to hide the Error Code and Error Text, please consider logging this information in a location where the merchant can easily locate it.

 


As a reminder, if you have comments, please post them in this comment thread:

https://community.developer.authorize.net/t5/Community-Feedback/Request-for-Comments-API-Best-Practi...