Giter Site home page Giter Site logo

kbs1 / laravel-encrypted-api Goto Github PK

View Code? Open in Web Editor NEW
25.0 4.0 4.0 21 KB

Encrypted API communication between Laravel applications

License: MIT License

PHP 100.00%
laravel-5-package laravel api api-client api-server encryption decryption encrypted authentication mitm man-in-the-middle man-in-the-middle-attack security

laravel-encrypted-api's Introduction

Laravel Encrypted API

Create encrypted API communication between Laravel applications in a breeze. Request and response data is transmitted securely using a two-way cipher, everything is checksummed to prevent modification (MITM attacks) in any way.

This package is meant to be used in both the client and server applications. Since it handles both receiving the request (verifying and decrypting) and sending a request / response (encrypting and signing), the whole implementation is seamless and based only on a middleware.

The middleware transparently modifies the incoming request and replaces the request data with decrypted values, so you can use your own FormRequests, validation or any other code that you would normally use with a standard request (for example $request->input('foo') inside controllers and so on).

You can extend the middleware to satisfy any specific needs you might have (for example multiple clients communicating securely each with it's own set of shared secrets).

The called API routes should be served using HTTPS for extra security, but this is not a requirement.

This package authenticates the calling client, since no other caller knows the shared secrets. This ensures your API is securely called only from applications under your or approved 3rd party control, even if the API routes themselves are publicly open to the internet.

Installation

composer require kbs1/laravel-encrypted-api

The package is now installed. If you are using laravel version < 5.5, add the following line in your config/app.php providers section:

Kbs1\EncryptedApi\Providers\EncryptedApiServiceProvider::class,

Configuration

By default, the package supports encrypted communication with exactly one client, with one pair of shared secrets. First publish the config using php artisan vendor:publish --tag=encrypted-api and set the appropriate secret1 and secret2 values (minimum 32 bytes in length, for secret1, only the first 32 bytes are used). Do the same in your other application and you are ready to go!

For your convenience, php artisan encrypted-api:secrets:generate command is included to generate suitable shared secrets. Pass the --save option to automatically publish the config if it hasn't been published already, and modify the config file in-place with new shared secrets. After executing the command with the --save option, you can view the generated secrets by opening config/encrypted_api.php. In any case, copy the shared secrets to your other application and your configuration is complete!

Usage

Once the package is installed, it automatically registers the kbs1.encryptedApi middleware alias. You can use this alias in any routes you would like to secure using this package.

Receiving requests (server application)

Route::group(['prefix' => '/api', 'middleware' => ['kbs1.encryptedApi']], function () {
	Route::post('/users/disable', 'App\Http\Controllers\Api\UsersController@disable')->name('myApp.api.users.disable');
	...
});

Above example automatically secures the route group using this package, any calls to the group must now be sent only using authenticated client application. Default middleware implementation uses shared secrets defined in config/encrypted_api.php.

You can easily support multiple calling clients with secrets stored for example in a database. Extend the Kbs1\EncryptedApi\Http\Middleware\EncryptedApi class and implement your own getSharedSecrets() method:

class ClientApi extends \Kbs1\EncryptedApi\Http\Middleware\EncryptedApi
{
	protected function getSharedSecrets($request)
	{
		$client = \App\Clients\ClientRepository::findByUuid($request->route('clientUuid'));
		return ['secret1' => $client->secret1, 'secret2' => $client->secret2];
	}
}

In the above example, the route group might look like this:

Route::group(['prefix' => '/api/{clientUuid}', 'middleware' => ['clientApi']], function () {
	Route::post('/users/disable', 'App\Http\Controllers\Api\Clients\UsersController@disable')->name('myApp.api.clients.users.disable');
	...
});

Sending requests (caller application)

Calling encrypted API service can be accomplished in the following way:

$call = new \Kbs1\EncryptedApi\Http\ApiCall("https://server-application.dev/api/$ourUuid/users/disable", 'POST', [
	'user_uuid' => '...',
	'parameter1' => true,
	'parameter2' => 'foo',
	...
], $secret1, $secret2);

try {
	$response = $call->execute(); // will execute the call each time invoked
} catch (\Kbs1\EncryptedApi\Exceptions\EncryptedApiException $ex) {
	...
}

// retrieve service response later if desired
$response = $call->response();
$http_status_code = $call->httpStatus();
$response_headers = $call->headers();

$response will contain any response sent by the service. This might be JSON or any other service response you implement. All service responses protected by this package are always properly signed and encrypted before sending, even if an exception occurs (invalid request data, crashes in your service and so on). This means no one, without knowing the required shared secrets, is able to read the service response in any case.

ApiCall constructor can take either collection or array as the third optional data argument. Fourth and fifth arguments (secret1 and secret2) are optional as well and if they are omitted, shared secrets are loaded from config/encrypted_api.php file.

For GET requests, the package will send a request body as well. This ensures the request must also be properly signed, and no one except the authorised caller can call the route.

A note on query string and route parameters

It is adivsed to send each API service parameter using third (data) argument of the ApiCall class only (even for GET requests). Althrough the package verifies the exact URL that was called (including query string and HTTP method) on the server side, sensitive data passed as query parameters or route segments can still be captured for example in server's access log.

Securely passed parameters (third data argument) always overwrite query string paramets, using Laravel's $request->merge() method.

The only parameter that is advised to be passed as query string parameter or route segment is the clientUuid parameter, should you have multiple calling clients. As this parameter is used to load shared secrets for particular client, it can not be passed encrypted.

IP whitelists

If you want to ensure API calls from a certain client come only from whitelisted IPv4 addresses, you can set appropriate ipv4_whitelist array in config/encrypted_api.php. To provide your own whitelist based on clientUuid or any other client identifier (when you have multiple calling clients), override getAllowedIps method in your own route middleware class:

class ClientApi extends \Kbs1\EncryptedApi\Http\Middleware\EncryptedApi
{
	protected function getAllowedIps($request)
	{
		$client = \App\Clients\ClientRepository::findByUuid($request->route('clientUuid'));
		return [$client->ipv4];
	}
}

Replay attacks

This package protects using simple replay attacks, as each signed request and response has it's unique identifier, and is only valid for 10 seconds. Implementation automatically stores each received identifier in the last 10 seconds on the server side, and discards any processing when encountering already processed request identifier.

laravel-encrypted-api's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

laravel-encrypted-api's Issues

Laravel version

I think it should require laravel/framework and not laravel/laravel, since Laravel/Laravel is the application template/skeleton.

Tried to install and got error:

Problem 1
- Installation request for kbs1/laravel-encrypted-api v1.0 -> satisfiable by kbs1/laravel-encrypted-api[v1.0].
- kbs1/laravel-encrypted-api v1.0 requires laravel/laravel >=5.4 -> no matching package found.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.