kynx / api-key-generator
生成和解析有效的API密钥
Requires
- php: ~8.2
- ircmaxell/random-lib: ^1.2
Requires (Dev)
- laminas/laminas-coding-standard: ^2.3
- phpunit/phpunit: ^10.2
- psalm/plugin-phpunit: ^0.18.4
- squizlabs/php_codesniffer: ^3.7
- vimeo/psalm: ^5.13
README
生成和解析有效的API密钥。
简介
API密钥是验证用户访问API的一种常见方式。虽然没有标准说明它们应该如何构建,但有一些最佳实践。
API密钥应该
- 是安全的(好吧,这有点明显...)
- 不会泄露与其关联的用户身份的任何信息
- 易于安全存储和验证持久层
- 可追踪,以防某个笨蛋将其检查到VCS中 - 例如,使用GitHub的Secret Scanning
- 提供一种方法,可以快速拒绝明显格式错误的密钥,而无需击中持久层
- 包含可读信息,以便最终用户/支持人员可以轻松地查看他们是否正在使用正确的密钥
- 易于从UI复制粘贴到消费应用程序
这个库有助于实现这一点,提供了一个用于生成和解析密钥的ApiKeyGenerator
,以及一个用于处理密钥本身的ApiKey
对象。它不提供存储和验证密钥的帮助 - 这部分由你自己负责。
安装
composer require kynx/api-key-generator
用法
生成密钥
use Kynx\ApiKey\KeyGenerator; require 'vendor/autoload.php'; $generator = new KeyGenerator('xyz_sandbox'); $apiKey = $generator->generate(); echo $apiKey->getKey() . "\n";
这将输出类似以下内容
xyz_sandbox_miWh6l3ftyzi9TRmpZeJ4nU3LpBF5T37FguT1p4y_dab13e9d
请参阅 示例 目录,其中包含如何修改密钥强度、更改使用的字符等代码。
解析密钥
use Kynx\ApiKey\KeyGenerator; require 'vendor/autoload.php'; $generator = new KeyGenerator('xyz_sandbox'); $apiKey = $generator->parse('xyz_sandbox_miWh6l3ftyzi9TRmpZeJ4nU3LpBF5T37FguT1p4y_dab13e9d'); if ($apiKey === null) { echo "Invalid key!\n"; } else { echo "Identifier : " . $apiKey->getIdentifier() . "\n"; echo "Secret : " . $apiKey->getSecret() . "\n"; }
由于密钥是格式良好的,这将输出
Identifier : miWh6l3f
Secret : tyzi9TRmpZeJ4nU3LpBF5T37FguT1p4y
现在对密钥进行随机更改。parse()
方法将返回null
,您将看到“无效密钥!”消息。
注意:密钥格式良好并不意味着用户可以进行认证。它只是意味着它看起来是由您生成的。您必须仍然验证密钥与您的持久存储。
处理旧密钥
如果您更改密钥的前缀,或者想要增加密钥的密钥强度(见下文),会发生什么?您将希望使用更新的设置颁发所有新的密钥,但仍需要解析旧密钥。
这就是KeyGeneratorChain
的作用所在
use Kynx\ApiKey\KeyGenerator; use Kynx\ApiKey\KeyGeneratorChain; require '../vendor/autoload.php'; $newPrefix = 'abc_sandbox'; $oldPrefix = 'xyz_sandbox'; $primary = new KeyGenerator($newPrefix); $fallback = new KeyGenerator($oldPrefix); $chain = new KeyGeneratorChain($primary, $fallback); $oldKey = $chain->parse('xyz_sandbox_miWh6l3ftyzi9TRmpZeJ4nU3LpBF5T37FguT1p4y_dab13e9d'); if ($oldKey !== null) { echo "Old key parsed\n"; } $newKey = $chain->parse('abc_sandbox_miWh6l3ftyzi9TRmpZeJ4nU3LpBF5T37FguT1p4y_dab13e9d'); if ($newKey !== null) { echo "New key parsed\n"; }
新密钥始终由$primary
KeyGenerator生成。在解析时,首先尝试$primary
。如果返回null,将依次尝试每个$fallback
KeyGenerator,直到返回第一个成功的解析结果,或者如果没有任何匹配项,则返回null。请参阅parse-chain以获取更完整的示例。
API密钥结构
您会注意到在上述示例中,生成的密钥由三个部分组成,由下划线分隔。它们是
<prefix>_<identifier><secret>_<checksum>
前缀
前缀始终是传递给KeyGenerator构造函数的第一个参数。它的目的是使密钥易于识别,既便于最终用户,也便于在野外找到泄露的密钥的秘密扫描器。在我们的示例中,我们使用了一个公司标识符(xyz
)以及一个表示它是用于我们的production
或sandbox
环境的字符串。如果您曾经与Stripe集成过,您将熟悉这种模式,但您可以使用任何有意义的格式。
标识符
标识符
是一个随机字符串,可以用来在数据库中查找密钥。请将其以区分大小写的形式存储在未哈希的列中(例如,MySQL中的VARBINARY
),并对其施加唯一约束。生成的标识符不一定是唯一的,因此在将数据插入数据库时,您应该准备好捕获约束违规,生成新的密钥并重新尝试。有关示例,请参阅存储和认证。
密钥
密钥
部分提供了安全性。在存储之前,必须对它进行哈希处理(使用PHP的password_hash())。如果您不确定如何进行此操作,请参阅存储和认证示例代码。
校验和
最后,校验和
是其余密钥的crc32b
哈希值。它的目的是快速过滤掉攻击你的API的垃圾数据,而无需麻烦你的持久化层。仅仅因为匹配并不意味着用户可以认证!您仍然需要检查标识符和密钥是否与生成密钥时存储的内容相匹配。
默认值
默认情况下,标识符
长度为8个字符。使用默认字符,这给出了pow(59, 8) - 1
种组合。即使存储了数百万个密钥,碰撞的风险也非常小。鉴于API密钥仅适用于组织级别的访问控制,这应该足够了。但如果需要,您可以将其增加。
默认情况下,密钥
长度为32个字符。您可以增加此值来提高API的安全性。请参阅生成安全密钥示例。
默认情况下,生成的密钥部分由字符[a-zA-Z0-9_]
组成。您应该确保您的前缀
也是如此:这使得从密钥管理控制台复制它变得很容易。尝试双击xyz-sandbox_Pu!Lo&jP_N22/Oh5hz48h4.QM_e07f9ca3
以查看其他字符存在时会发生什么。如果您想要更多的熵,请使密钥更长。
升级
1.x -> 2.x
在1.x中,默认密钥长度为16个字符。尽管我讨厌BC不兼容,但这对于提倡最佳实践的库来说太低了。在2.x中,默认值为32,最小值为24。我认为最好早点纠正这个错误。
为了在不破坏现有密钥的情况下升级,您需要使用KeyGeneratorChain
以及用于解析旧密钥的BC生成器。
use Kynx\ApiKey\BcKeyGenerator; use Kynx\ApiKey\KeyGenerator; use Kynx\ApiKey\KeyGeneratorChain; require 'vendor/autoload.php'; $primary = new KeyGenerator('xyz_sandbox'); $fallback = new BcKeyGenerator('xyz_sandbox'); $chain = new KeyGeneratorChain($primary, $fallback); $newKey = $chain->generate(); // get a new 2.x key $oldKey = $chain->parse('xyz_sandbox_PudLoQjP_N227Oh5hz48h4FQM_e07f9ca3'); // 1.x key still parsed
BcKeyGenerator
不能用于生成新密钥,只能用于解析旧密钥。它和相关联的BcApiKey
已被弃用,将在3.x版本中删除。
进一步阅读
- https://zuplo.com/blog/2022/12/01/api-key-authentication 此包的原始灵感。包括有关管理和轮换密钥的附加有用信息。
- https://blog.mergify.com/api-keys-best-practice/ 覆盖了许多相同的内容,但结尾的清单对于评估API密钥的安全性很有用。人们将会评估您的!
- https://cheatsheetseries.owasp.ac.cn/cheatsheets/Key_Management_Cheat_Sheet.html OWASP密钥管理备忘单。