• Stars
    star
    317
  • Rank 127,162 (Top 3 %)
  • Language
    PHP
  • License
    MIT License
  • Created almost 7 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Secure API Toolkit

Sapient: Secure API toolkit

Build Status Latest Stable Version Latest Unstable Version License

Sapient secures your PHP applications' server-to-server HTTP(S) traffic even in the wake of a TLS security breakdown (compromised certificate authority, etc.).

Sapient allows you to quickly and easily add application-layer cryptography to your API requests and responses. Requires PHP 7 or newer.

Sapient was designed and implemented by the PHP security and cryptography team at Paragon Initiative Enterprises.

See our blog post about using Sapient to harden your PHP-powered APIs for more information about its design rationale and motivation.

The cryptography is provided by sodium_compat (which, in turn, will use the libsodium extension in PECL if it's installed).

Because sodium_compat operates on strings rather than resources (a.k.a. streams), Sapient is not suitable for extremely large messages on systems with very low available memory. Sapient only encrypts or authenticates message bodies; if you need headers to be encrypted or authenticated, that's the job of Transport-Layer Security (TLS).

Features at a Glance

  • Works with both Request and Response objects (PSR-7)
    • Includes a Guzzle adapter for HTTP clients
  • Secure APIs:
    • Shared-key encryption
      • XChaCha20-Poly1305
    • Shared-key authentication
      • HMAC-SHA512-256
    • Anonymous public-key encryption
      • X25519 + BLAKE2b + XChaCha20-Poly1305
    • Public-key digital signatures
      • Ed25519
  • Works with arrays
    • i.e. the methods with "Json" in the name
    • Sends/receives signed or encrypted JSON
  • Works with strings
    • i.e. the methods without "Json" in the name
  • Digital signatures and authentication are backwards-compatible with unsigned JSON API clients and servers
    • The signaure and authentication tag will go into HTTP headers, rather than the request/response body.

Additionally, Sapient is covered by both unit tests (provided by PHPUnit) and automated static analysis (provided by Psalm).

Sapient Adapters

If you're looking to integrate Sapient into an existing framework:

If your framework correctly implements PSR-7, you most likely do not need an adapter. However, some adapters provide convenience methods that make rapid development easier.

To learn more about adapters, see the documentation for AdapterInterface.

Sapient in Other Languages

Example 1: Signed PSR-7 Responses

This demonstrats a minimal implementation that adds Ed25519 signatures to your existing PSR-7 HTTP responses.

Server-Side: Signing an HTTP Response

<?php
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
use Psr\Http\Message\ResponseInterface;

/**
 * @var ResponseInterface $response
 *
 * Let's assume we have a valid ResponseInterface object already.
 * (Most likely, after doing normal framework things.)  
 */

$sapient = new Sapient();
$serverSignSecret = new SigningSecretKey(
    Base64UrlSafe::decode(
        'q6KSHArUnD0sEa-KWpBCYLka805gdA6lVG2mbeM9kq82_Cwg1n7XLQXXXHF538URRov8xV7CF2AX20xh_moQTA=='
    )
);

$signedResponse = $sapient->signResponse($response, $serverSignSecret);

Client-Side: Verifying the Signature

<?php
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
use ParagonIE\Sapient\Exception\{
    HeaderMissingException,
    InvalidMessageException
};
use Psr\Http\Message\ResponseInterface;

/**
 * @var ResponseInterface $response
 *
 * Let's assume we have a valid ResponseInterface object already.
 * (Most likely the result of an HTTP request to the server.)  
 */

$sapient = new Sapient();
$serverPublicKey = new SigningPublicKey(
    Base64UrlSafe::decode(
        'NvwsINZ-1y0F11xxed_FEUaL_MVewhdgF9tMYf5qEEw='
    )
);

try {
    $verified = $sapient->verifySignedResponse($response, $serverPublicKey);
} catch (HeaderMissingException $ex) {
    /* The server didn't provide a header. Discard and log the error! */
} catch (InvalidMessageException $ex) {
    /* Invalid signature for the message. Discard and log the error! */
}

Example 2: Mutually Signed JSON API with the Guzzle Adapter

This example takes advantage of an Adapter the provides the convenience methods described in ConvenienceInterface.

Client-Side: Sending a Signed Request, Verifying the Response

<?php
use GuzzleHttp\Client;
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Adapter\Guzzle as GuzzleAdapter;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
use ParagonIE\Sapient\Exception\InvalidMessageException;

$http = new Client([
    'base_uri' => 'https://your-api.example.com'
]);
$sapient = new Sapient(new GuzzleAdapter($http));

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

// We use an array to define our message
$myMessage = [
    'date' => (new DateTime)->format(DateTime::ATOM),
    'body' => [
        'test' => 'hello world!'        
    ]
];

// Create the signed request:
$request = $sapient->createSignedJsonRequest(
    'POST',
     '/my/api/endpoint',
     $myMessage,
     $clientSigningKey
);

$response = $http->send($request);
try {
    /** @var array $verifiedResponse */
    $verifiedResponse = $sapient->decodeSignedJsonResponse(
        $response,
        $serverPublicKey
    );
} catch (InvalidMessageException $ex) {
    \http_response_code(500);
    exit;
}

Server-Side: Verifying a Signed Request, Signing a Response

 <?php
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\ServerRequest;
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\Sapient\Adapter\Guzzle as GuzzleAdapter;
use ParagonIE\Sapient\Sapient;
use ParagonIE\Sapient\CryptographyKeys\SigningPublicKey;
use ParagonIE\Sapient\CryptographyKeys\SigningSecretKey;
use ParagonIE\Sapient\Exception\InvalidMessageException;

$http = new Client([
    'base_uri' => 'https://your-api.example.com'
]);
$sapient = new Sapient(new GuzzleAdapter($http));
 
$clientPublicKey = new SigningPublicKey(
    Base64UrlSafe::decode(
        'aX7Yu9kfAcvF5yDEyfB2w05LO4yuRpgJ77c2o9623Ew='
    )
);
$request = ServerRequest::fromGlobals();
try {
    /** @var array $decodedRequest */
    $decodedRequest = $sapient->decodeSignedJsonRequest(
        $request,
        $clientPublicKey
    );
} catch (InvalidMessageException $ex) {
    \http_response_code(500);
    exit;
}

/* Business logic goes here */

// Signing a response:
$serverSignSecret = new SigningSecretKey(
    Base64UrlSafe::decode(
        'q6KSHArUnD0sEa-KWpBCYLka805gdA6lVG2mbeM9kq82_Cwg1n7XLQXXXHF538URRov8xV7CF2AX20xh_moQTA=='
    )
);

$responseMessage = [
    'date' => (new DateTime)->format(DateTime::ATOM),
    'body' => [
        'status' => 'OK',
        'message' => 'We got your message loud and clear.'
    ]
];

$response = $sapient->createSignedJsonResponse(
    200,
    $responseMessage,
    $serverSignSecret
);
/* If your framework speaks PSR-7, just return the response object and let it
   take care of the rest. */

More Repositories

1

random_compat

PHP 5.x support for random_bytes() and random_int()
PHP
8,139
star
2

awesome-appsec

A curated list of resources for learning about application security
PHP
5,946
star
3

paseto

Platform-Agnostic Security Tokens
PHP
3,183
star
4

halite

High-level cryptography interface powered by libsodium
PHP
1,109
star
5

sodium_compat

Pure PHP polyfill for ext/sodium
PHP
855
star
6

constant_time_encoding

Constant-Time Character Encoding in PHP Projects
PHP
754
star
7

easydb

Easy-to-use PDO wrapper for PHP projects.
PHP
728
star
8

csp-builder

Build Content-Security-Policy headers from a JSON file (or build them programmatically)
PHP
537
star
9

chronicle

Public append-only ledger microservice built with Slim Framework
PHP
468
star
10

airship

Secure Content Management for the Modern Web - "The sky is only the beginning"
PHP
419
star
11

ciphersweet

Fast, searchable field-level encryption for PHP projects
PHP
415
star
12

anti-csrf

Full-Featured Anti-CSRF Library
PHP
293
star
13

certainty

Automated cacert.pem management for PHP projects
PHP
262
star
14

EasyRSA

Simple and Secure Wrapper for phpseclib
PHP
194
star
15

password_lock

Wraps Bcrypt-SHA2 in Authenticated Encryption
PHP
190
star
16

sodium-plus

Developer-friendly libsodium interface
JavaScript
170
star
17

multi_factor

Vendor-Agnostic Two-Factor Authentication
PHP
142
star
18

gpg-mailer

GnuPG-encrypted emails made easy
PHP
95
star
19

pecl-libsodium-doc

Free Online Documentation for the Libsodium PHP Extension
88
star
20

corner

Exceptions and Errors made more user-friendly
PHP
61
star
21

hidden-string

The HiddenString class extracted from Halite.
PHP
58
star
22

ciphersweet-js

Searchable Encryption for Node.js projects
JavaScript
58
star
23

iaso

Powerful JSON Toolkit, includes a JSON parser immune to Hash-DoS attacks
PHP
51
star
24

paseto-io

Paseto Website
Twig
46
star
25

hpkp-builder

Build HTTP Public-Key-Pinning headers from a JSON file (or build them programmatically)
PHP
41
star
26

seedspring

Seeded, Deterministic PRNG (based on AES-CTR instead of LCG)
PHP
40
star
27

easy-ecc

High-Level Usability Wrapper for PHPECC
PHP
39
star
28

passwdqc

Password/passphrase strength checking and enforcement (PHP port)
PHP
39
star
29

pharaoh

Utility to quickly and effectively diff two PHP Archives
PHP
37
star
30

libgossamer

Public Key Infrastructure without Certificate Authorities, for WordPress and Packagist
PHP
31
star
31

easydb-cache

EasyDB with Prepared Statement Caching
PHP
29
star
32

ionizer

Input Filter System for PHP Software
PHP
26
star
33

argon2-refiner

Generate Parameter Recommendations for Argon2id in PHP 7.3+
PHP
24
star
34

bsidesorl-2017

Supplementary Material for Building Defensible Solutions to Weird Problems
PHP
23
star
35

blakechain

Hash chains built with BLAKE2b
PHP
22
star
36

quill

Library for quickly and easily writing data to a Chronicle instance
PHP
21
star
37

stern

Stern lets you built type-safe PHP projects, even if your project's users aren't writing type-safe code
PHP
20
star
38

herd

Hash-Ensured Replicated Database
PHP
16
star
39

eloquent-ciphersweet

Bridge library between Eloquent ORM and CipherSweet
PHP
14
star
40

pco_prototype

PCO - PHP Crypto Objects
PHP
12
star
41

discretion

On-demand and reusable contact forms that only send GnuPG-encrypted messages to your inbox.
PHP
12
star
42

xchacha20-js

JavaScript implementation of ChaCha20, HChaCha20, and XChaCha20
JavaScript
11
star
43

slim-sapient

Slim Framework Adapter for Sapient
PHP
10
star
44

airship-docs

Documentation for CMS Airship
Nginx
10
star
45

paserk-php

PHP Implementation of PASERK
PHP
10
star
46

php-jwt-guard

Security Defense for Firebase's PHP-JWT Library
PHP
9
star
47

zend-diactoros-sapient

Zend Diactoros Adapter for Sapient
PHP
8
star
48

phone-to-pick

Whitelist Your Incoming Phone Calls (for Android)
Java
7
star
49

poly1305-js

JavaScript implementation of the Poly1305 one-time authenticator
JavaScript
5
star
50

gossamer-server

Standalone Gossamer server
PHP
4
star
51

paseto-browser.js

PASETO in the Web Browser
JavaScript
4
star
52

airship-barge

Build Gadgets for Airship projects (Command Line Interface)
PHP
3
star
53

monolog-quill

A Monolog Handler for writing to a Chronicle instance
PHP
3
star
54

sodium-jvm

Pure-Java implementation of the Sodium cryptography library.
3
star
55

blogpost-translations

Translations of Paragon Initiative Enterprise blog posts
2
star
56

ward-docs

Online Documentation for Ward (Web Application Realtime Defender)
2
star
57

php71_crypto

Pluggable Cryptography Interface for PHP 7.1
2
star
58

node-halite

High-level cryptography interface powered by node-sodium
1
star
59

ristretto-php

Implements a type-safe API for working with the Ristretto Group in PHP projects.
PHP
1
star
60

pie-hosted.com

Source code for the pie-hosted.com website
PHP
1
star
61

halite-legacy

Legacy versions of Halite to facilitate migrations from older ciphersuites to the latest supported version
PHP
1
star
62

certainty-js

Certainty-js: Automated CACert.pem Management for Node.js Software
JavaScript
1
star