Paragon Initiative Enterprises Blog

The latest information from the team that develops cryptographically secure PHP software.

Hardening Your PHP-Powered APIs with Sapient

The most fundamental requirement for any website to be secure is to use HTTPS (formally defined as HTTP over TLS, and preferably TLS 1.2 or 1.3). However, HTTPS alone does not satisfy every company's security needs.

In the typical HTTPS usage, the server is authenticated to the client, but not vice-versa. (You can play with TLS client certificates, but they're too cumbersome for most software developers.)

Certificate authorities can behave abusively or get outright hacked.

The defense-in-depth strategy for untrusted CAs is public-key pinning, but for PHP developers, enforcing public-key pinning isn't straightforward (or always possible, depending on how old your software is).

What if we told you we've developed a PHP library that solves all of these problems for your APIs, that works with PSR-7 HTTP messages, carries minimal added complexity, and just released the source code on Github?

Sapient: Secure API Toolkit

Sapient is a PHP library that wraps Guzzle and sodium_compat to add secure application-layer cryptography to your server-to-server HTTP requests. Some of its features, at a glance:

  • Operates on PSR-7 Request and Response objects (provided by Guzzle)
  • Public-Key Cryptography
    • Public-key Digital Signatures (Signing)
    • Public-key Message Encryption (Sealing)
  • Secret-Key Cryptography
    • Shared-key Message Authentication
    • Shared-key Message Encryption
  • Backwards-Compatibility with Unsecured APIs
    • Both Public-Key Signatures and Secret-Key Authentication add/verify an HTTP header but don't touch the message body at all
    • Servers that don't check the request headers will proceed as normal
    • Clients that don't check the response headers will proceed as normal
    • Clients/servers that do expect a request/response header will fail closed if one is not present

Ed25519-Signed API Communications with Sapient

Let's say you have an HTTP request you want to send to a Sapient-aware API, which is signed by a secret key only your application possesses. (Your API provider only knows your public key.)

All you need to do is:

  1. Pass your Request object to Sapient::signRequest() with your secret key.
  2. Pass the Response object to Sapient::verifySignedResponse() with your API's public key.

A detail client-side example of a secure two-way communication using PSR-7 looks like this:

<?php

use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
use ParagonIE\Sapient\Exception\HeaderMissingException;
use ParagonIE\Sapient\Exception\InvalidMessageException;

/* Load keys */
$clientSigningKey = new SigningSecretKey(
    Base64UrlSafe::decode(
        'AHxoibWhTylBMgFzJp6GGgYto24PVbQ-ognw9SPnvKppfti72R8By8XnIMTJ8HbDTks7jK5GmAnvtzaj3rbcTA=='
    )
);
$serverPublicKey = new SigningPublicKey(
    Base64UrlSafe::decode(
        'NvwsINZ-1y0F11xxed_FEUaL_MVewhdgF9tMYf5qEEw='
    )    
);

/* Initiate Sapient */
$sapient = new Sapient([
    'base_url' => 'https://api-provider.example.com'
]);

/** @var RequestInterface */
$request = $yourApp->getRequestToSend();

/* Create a signed request */
$signedRequest = $sapient->createSignedRequest(
    $request,
    $clientSigningKey
);

/* Get send the request to the server, grab the response */
$response = $sapient->send($signedRequest);
try {
    /* Verify the signature */
    $trustedApiResponse = $sapient->verifySignedResponse(
        $response,
        $serverPublicKey
    );
} catch (HeaderMissingException $exception) {
    /* No header added. */
    exit;
} catch (InvalidMessageException $exception) {
    /* Invalid signature */
    exit;
}

If you're building an API and you use Sapient in a PSR-7 middleware to sign your HTTP responses, non-Sapient clients that consume your API will be unaffected. At worst, they have one more HTTP header to disregard. Likewise, the converse is true: If you're building a Sapient API client that signs its HTTP requests, unless the non-Sapient API you're communicating with is particularly fussy about superfluous headers, this will not inhibit communication.

However, if both sides are using Sapient, then downgrade attacks are no longer possible. If a signature is expected, it will not silently fail.

Who Should Consider Adopting Sapient?

First and foremost: Payment Gateways. In addition to digital signatures, Sapient allows quick and easy asymmetric encryption with a hard-coded public key that you can provide your users, which will in turn prevent a certificate authority meltdown from compromising the confidentiality of the messages sent over HTTPS.

$response = $sapient->send(
    $sapient->sealRequest($request, $serverX25519PublicKey)
);
$decrypted = $sapient->unsealResponse($response, $clientX25519SecretKey);

Beyond the realm of e-commerce, API clients and providers that either need a high degree of security or just want an easy way to mutually authenticate clients and servers should consider making their API gateway Sapient-compatible.

Anticipated Questions

Will Sapient be available in other languages besides PHP?

Eventually, yes. Priority will be given to paid client work and our in-house development needs. If you need a library written in your favorite programming language, get in touch. All of the cryptography is provided by libsodium, so any language that has libsodium bindings is a good candidate for a Sapient implementation.

What is the roadmap for development?

After our documentation and unit tests are up to snuff, we'll write a formal specification that details how to write compatible interfaces in other languages. Then, we will tag version 1.0, which will be supported until PHP 7.1 has reached end-of-life.

Version 2.0, to be released in 2018, will require PHP 7.2 and not sodium_compat (since libsodium is going to be a core extension).

Will Sapient support PHP 5?

No.

We're willing to develop a proprietary fork that supports PHP 5.6 (until it has reached end-of-life), but that will not be released to the general public. Upgrade to PHP 7 if you want better security and performance.

About the Author

P.I.E. Staff

Paragon Initiative Enterprises

Paragon Initiative Enterprises is a Florida-based company that provides software consulting, application development, code auditing, and security engineering services. We specialize in PHP Security and applied cryptography.


Need Technology Consultants?

Will tomorrow bring costly and embarrassing data breaches? Or will it bring growth, success, and peace of mind?

Our team of technology consultants have extensive knowledge and experience with application security and web/application development.

We specialize in cryptography and secure PHP development.

Let's Work Together Towards Success

Our Security Newsletters

Want the latest from Paragon Initiative Enterprises delivered straight to your inbox? We have two newsletters to choose from.

The first mails quarterly and often showcases our behind-the-scenes projects.

The other is unscheduled and gives you a direct feed into the findings of our open source security research initiatives.

Quarterly Newsletter   Security Announcements