jeremykendall/query-auth

REST API查询认证的签名生成和验证

4.0.0-alpha 2013-08-19 13:58 UTC

README

master: 构建状态 develop: 构建状态

REST API查询认证的签名生成和验证

API查询认证

大多数API需要某种形式的查询认证,通常是通过使用API密钥和签名来签名API请求。签名通常使用共享密钥生成。当你消费API时,创建签名通常有(希望是)易于遵循的步骤。当你编写自己的API时,你必须为服务器端签名验证策略和客户端签名创建策略。这个库旨在为你处理这两个任务。

示例实现

一个Query Auth库的示例实现可用,以更好地展示如何使用该库。

用法

该库有三个组件

  • 请求签名
  • 请求验证
  • API密钥和密钥生成

请求签名和验证是通过使用请求适配器实现的。

请求适配器

Query Auth请求适配器封装出发和到达的请求,并将它们适配到Query Auth期望的请求接口。

出发

出发请求适配器用于促进请求签名。目前,在QueryAuth\Request\Adapter\Outgoing命名空间中有两个可用

  • GuzzleRequestAdapter用于Guzzle v3
  • GuzzleHttpRequestAdapter用于Guzzle v4

到达

到达请求适配器用于促进请求验证。目前,在QueryAuth\Request\Adapter\Incoming命名空间中有一个可用

  • SlimRequestAdapter用于Slim PHP v2

自定义

如果你希望使用除了Guzzle之外的HTTP库,或者如果你希望使用除了Slim之外的应用程序框架,你需要编写自己的请求适配器。请参阅现有的请求适配器以获取示例。

请求签名

use GuzzleHttp\Client as GuzzleHttpClient;
use QueryAuth\Credentials\Credentials;
use QueryAuth\Factory;
use QueryAuth\Request\Adapter\Outgoing\GuzzleHttpRequestAdapter;

$factory = new Factory();
$requestSigner = $factory->newRequestSigner();
$credentials = new Credentials('key', 'secret');

// Create a GET request and set an endpoint
$guzzle = new GuzzleHttpClient(['base_url' => 'http://api.example.com']);
$request = $guzzle->createRequest('GET', '/endpoint');

// Sign the request
$requestSigner->signRequest(new GuzzleHttpRequestAdapter($request), $credentials);

// Send signed request
$response = $guzzle->send($request);

请求验证

use QueryAuth\Credentials\Credentials;
use QueryAuth\Factory;
use QueryAuth\Request\Adapter\Incoming\SlimRequestAdapter;

$factory = new Factory();
$requestValidator = $factory->newRequestValidator();
$credentials = new Credentials('key', 'secret');

// Get the Slim request (in the context of a Slim route, hook, or middleware)
$request = $app->request;

// $isValid is a boolean
$isValid = $requestValidator->isValid(new SlimRequestAdapter($request), $credentials);

RequestValidator::isValid()将返回true或false。它也可能抛出三种异常之一

  • DriftExceededException:如果时间戳超出+- RequestValidator::$drift
  • SignatureMissingException:如果请求参数中缺少签名
  • TimestampMissingException:如果请求参数中缺少时间戳

Drift默认为15秒,这意味着有一个30秒的窗口,在此期间请求是有效的。默认值可以通过使用RequestValidator::setDrift()修改。

重放攻击预防

有许多策略可用于防止重放攻击。这里实施的策略遵循以下一般概述

  • 验证到达签名
  • 如果签名有效,检查存储层以查看该组合的API密钥和签名是否之前已经使用过
  • 如果已使用,则请求可能是重放攻击,应拒绝
  • 如果尚未设置,则持续使用API密钥、签名和过期时间戳
  • 定期清除超出过期时间戳的记录

重要:签名过期时间戳应大于最大允许的漂移。过早删除签名可能会使您容易受到重放攻击。

注意:实现重放攻击预防策略是可选的。这不是使用此库的要求。然而,非常推荐。

提供了QueryAuth\Storage\SignatureStorage接口,以帮助实现重放攻击预防。

<?php

namespace QueryAuth\Storage;

interface SignatureStorage
{
    public function exists($key, $signature);

    public function save($key, $signature, $expires);

    public function purge();
}

注意:实现SignatureStorage接口不是防止重放攻击的要求,它只是用于协助您实现上述策略的辅助工具。

密钥生成

您可以使用以下方式生成API密钥和密钥。

$factory = new QueryAuth\Factory();
$keyGenerator = $factory->newKeyGenerator();

// 40 character random alphanumeric string
$key = $keyGenerator->generateKey();

// 60 character random string containing the characters
// 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./
$secret = $keyGenerator->generateSecret();

键和密钥都使用Anthony Ferrara的RandomLib随机字符串生成器生成。

低于3.0+的版本已弃用,但未作废

虽然我建议尽快升级到v3,但在重构API而不更改签名创建和验证逻辑的情况下,一个令人愉快的副作用是Query Auth 3.0+与Query Auth的早期版本兼容。这意味着您可以在服务器端(验证)升级Query Auth,而无需立即升级所有客户端(创建)应用程序。额外奖励!

安装

包安装由Composer处理。

  • 如果您尚未安装,请安装Composer
  • 在项目的根目录中创建composer.json,并将query-auth添加为依赖项
{
    "require": {
        "jeremykendall/query-auth": "*"
    }
}
  • 运行composer install
  • 在您的引导/初始化脚本中需要Composer的vendor/autoload.php脚本

反馈和贡献

  • 欢迎以拉取请求和/或问题的形式提供反馈。
  • 贡献应一般遵循"向项目贡献"中概述的策略。
  • 请针对develop分支提交拉取请求

鸣谢

  • Query Auth是我对Signature Version 2实现的个人实现,该实现来自AWS SDK for PHP 2。因此,此分发包含Apache License Version 2.0的一个版本,以及AWS SDK for PHP 2 NOTICE文件的相关部分。

  • API密钥和API密钥生成由Anthony Ferrara的RandomLib随机字符串生成器处理。