redant/leclient

此包已被 弃用 并不再维护。未建议替代包。

PHP Let's Encrypt 客户端库,用于 ACME v2

1.1.7 2020-02-16 11:37 UTC

This package is auto-updated.

Last update: 2021-11-16 15:39:51 UTC


README

PHP Let's Encrypt 客户端库,用于 ACME v2。该客户端的目的是创建一个易于使用且集成的解决方案,使用 PHP 创建 Let's Encrypt 签发的 SSL/TLS 证书。用户必须能够访问 Web 服务器或 DNS 管理,以便验证域是可访问的/由用户拥有的。

当前版本

当前版本是 1.1.4

以下示例代码需要更新。

此客户端是使用 Let's Encrypt 的测试服务器开发的,用于版本 2。虽然目前 Let's Encrypt 仍在开发和实施版本 2,但项目可能会发生变化。

入门指南

以下说明将帮助您开始使用此客户端库。如果您有任何问题或遇到任何问题,请随时提交问题,我将尽力查看。

还可以查看 Let's Encrypt 文档 了解有关 Let's Encrypt 和 ACME 的更多信息。

先决条件

最低要求的 PHP 版本是 5.2.0。需要 7.1.0 版本才能使用 EC 密钥。当尝试使用低于 7.1.0 的 PHP 版本生成 EC 密钥时,生成 EC 密钥的函数将抛出异常。将保留 1.0.0 版本,但不再维护。

此客户端还依赖于 cURL 和 OpenSSL。

安装

使用 composer

composer require yourivw/leclient

尽管可以将此添加到自己的自动加载器中,但并不推荐这样做,因为您将无法控制依赖项。如果您之前没有使用过 composer,我强烈建议您查看 https://getcomposer.org.cn

建议设置更高的最大执行时间,以便在执行脚本时给予一些宽容。有多种方法可以实现这一点。一种方法是在页面顶部添加以下内容

ini_set('max_execution_time', 120); // Maximum execution time in seconds.

用法

此处显示了基本函数及其必要的参数。每个类中都包含扩展说明。


初始化客户端

use LEClient\LEClient;

$client = new LEClient($email);                               // Initiating a basic LEClient with an array of string e-mail address(es).
$client = new LEClient($email, true);                         // Initiating a LECLient and use the LetsEncrypt staging URL.
$client = new LEClient($email, true, LEClient::LOG_STATUS);   // Initiating a LEClient and log status messages (LOG_DEBUG for full debugging).

如果找不到客户端,它将自动创建一个新账户。它将转发在初始化过程中提供的电子邮件地址(如上所示)。


使用账户函数

$acct = $client->getAccount();  // Retrieves the LetsEncrypt Account instance created by the client.
$acct->updateAccount($email);   // Updates the account with new contact information. Supply an array of string e-mail address(es).
$acct->changeAccountKeys();     // Generates a new RSA keypair for the account and updates the keys with LetsEncrypt.
$acct->deactivateAccount();     // Deactivates the account with LetsEncrypt.

创建证书订单实例。如果找到本地存储的订单,则使用此订单。否则,将创建一个新订单。如果提供的域名与订单不匹配,则也会创建一个新订单。构造 Let's Encrypt 订单实例

$order = $client->getOrCreateOrder($basename, $domains);                          			// Get or create order. The basename is preferably the top domain name. This will be the directory in which the keys are stored. Supply an array of string domain names to create a certificate for.
$order = $client->getOrCreateOrder($basename, $domains, $keyType);              			// Get or create order. keyType can be set to "ec" to get ECDSA certificate. "rsa" is default value.
$order = $client->getOrCreateOrder($basename, $domains, $keyType, $notBefore);              // Get or create order. Supply a notBefore date as a string similar to 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss).
$order = $client->getOrCreateOrder($basename, $domains, $keyType, $notBefore, $notAfter);   // Get or create order. Supply a notBefore and notAfter date as a string similar to 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss).

使用订单函数

$valid      = $order->allAuthorizationsValid();                             // Check whether all authorizations in this order instance are valid.
$pending    = $order->getPendingAuthorizations($type);                      // Get an array of pending authorizations. Performing authorizations is described further on. Type is LEOrder::CHALLENGE_TYPE_HTTP or LEOrder::CHALLENGE_TYPE_DNS.
$verify     = $order->verifyPendingOrderAuthorization($identifier, $type);  // Verify a pending order. The identifier is a string domain name. Type is LEOrder::CHALLENGE_TYPE_HTTP or LEOrder::CHALLENGE_TYPE_DNS.
$deactivate = $order->deactivateOrderAuthorization($identifier);            // Deactivate an authorization. The identifier is a string domain name.
$finalize   = $order->finalizeOrder();                                      // Finalize the order and generate a Certificate Signing Request automatically.
$finalize   = $order->finalizeOrder($csr);                                  // Finalize the order with a custom Certificate Signing Request string.
$finalized  = $order->isFinalized();                                        // Check whether the order is finalized.
$cert       = $order->getCertificate();                                     // Retrieves the certificate and stores it in the keys directory, under the specific order (basename).
$revoke     = $order->revokeCertificate();                                  // Revoke the certificate without a reason.
$revoke     = $order->revokeCertificate($reason);                           // Revoke the certificate with a reason integer as found in section 5.3.1 of RFC5280.

辅助函数

use LEClient\LEFunctions;

LEFunctions::RSAGenerateKeys($directory, $privateKeyFile, $publicKeyFile);  // Generate a RSA keypair in the given directory. Variables privateKeyFile and publicKeyFile are optional and have default values private.pem and public.pem.
LEFunctions::ECGenerateKeys($directory, $privateKeyFile, $publicKeyFile);  	// Generate a EC keypair in the given directory (PHP 7.1+ required). Variables privateKeyFile and publicKeyFile are optional and have default values private.pem and public.pem.
LEFunctions::Base64UrlSafeEncode($input);                                   // Encode the input string as a base64 URL safe string.
LEFunctions::Base64UrlSafeDecode($input);                                   // Decode a base64 URL safe encoded string.
LEFunctions::log($data, $function);                                         // Print the data. The function variable is optional and defaults to the calling function's name.
LEFunctions::checkHTTPChallenge($domain, $token, $keyAuthorization);        // Checks whether the HTTP challenge is valid. Performing authorizations is described further on.
LEFunctions::checkDNSChallenge($domain, $DNSDigest);                        // Checks whether the DNS challenge is valid. Performing authorizations is described further on.
LEFunctions::createhtaccess($directory);									// Created a simple .htaccess file in the directory supplied, denying all visitors.

授权挑战

Let's Encrypt (ACME) 对您希望在证书中包含的域进行授权,以验证您实际上有权访问特定域名。因此,在创建订单时,为每个域名添加一个授权。如果一个域名在最近(在过去30天内)已经被您的账户验证过,例如在另一个订单中,您无需再次验证。此时,可以通过对文件进行HTTP请求(http-01)或DNS TXT记录(dns-01)来验证域名。客户端通过调用getPendingAuthorizations()提供所选验证所需的数据。由于创建文件或DNS记录对于每个服务器都不同,因此客户端没有实现这一点。在用户完成挑战要求后,必须调用verifyPendingOrderAuthorization()来验证。此客户端将首先通过checkHTTPChallenge()或checkDNSChallenge()自行验证挑战,然后再开始由Let's Encrypt进行验证。请注意,通配符域名只能通过DNS挑战进行验证。以下展示了两个挑战的示例。

HTTP挑战

对于此示例,我们假设还有一个域需要验证。

use LEClient\LEOrder;

$pending = $order->getPendingAuthorizations(LEOrder::CHALLENGE_TYPE_HTTP);

这将返回一个数组

Array
(
    [0] => Array
        (
            [type] => http-01
            [identifier] => test.example.org
            [filename] => A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb
            [content] => A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb.C4kIiiwfcynb3i48AQVtZRtNrD51z4JiIrdQsgVqcL8
        )
)

对于成功的验证,将向以下URL发出请求

http://test.example.org/.well-known/acme-challenge/A8Q1DAVcd_k_oKAC0D_y4ln2IWrRX51jmXnR9UMMtOb

此文件的应包含上述数组中的内容。用户应在验证授权之前创建此文件。

DNS挑战

对于此示例,我们假设还有两个域需要验证。其中一个是一个通配符域名。此示例中的第二个域名是用于演示目的添加的。向证书中添加一个子域名,这个子域名也已被通配符域名覆盖,并不会带来太多额外价值。

$pending = $order->getPendingAuthorizations(LEOrder::CHALLENGE_TYPE_DNS);

这将返回一个数组

Array
(
    [0] => Array
        (
            [type] => dns-01
            [identifier] => example.org
            [DNSDigest] => FV5HgbpjIYe1x9MkPI81Nffo2oA-Jo2S88gCL7-Ky5P
        )     
    [1] => Array
        (
            [type] => dns-01
            [identifier] => test.example.org
            [DNSDigest] => WM5YIsgaZQv1b9DbRZ81EwCf2fi-Af2JlgxTC7-Up5D
        )
)

对于成功的验证,DNS记录应创建如下

名称 TTL 类型
_acme-challenge.example.org 60 TXT FV5HgbpjIYe1x9MkPI81Nffo2oA-Jo2S88gCL7-Ky5P
_acme-challenge.test.example.org 60 TXT WM5YIsgaZQv1b9DbRZ81EwCf2fi-Af2JlgxTC7-Up5D

如果需要,可以将TTL值设置得更高,但我更喜欢将其保持得尽可能低。为了确保验证成功,建议使用两个部分的DNS挑战脚本,中间有一定的时间间隔,以便DNS记录更新。用户本人应确保在记录可以验证之前设置此DNS记录。DNS记录名称也取决于您的提供商,因此getPendingAuthorizations()不会提供现成的记录名称。某些提供商只接受像_acme-challenge这样的名称,没有顶级域名名称,用于_acme-challenge.example.org。某些提供商接受(要求?)如上所示的完整名称。

通配符域名,如*.example.org,将被验证为example.org,如上所示。这意味着DNS记录名称应为_acme-challenge.example.org

完整示例

对于HTTP和DNS授权,完整示例可在项目的主要代码目录中找到。HTTP授权示例包含在一个文件中。如上所述,DNS授权示例分为两部分,以便在中间更新DNS记录。虽然记录的TTL可能很低,但您的提供商在修改后更新DNS记录可能需要一些时间。

如果您无法获取这些示例或客户端库,请尝试查看上述提到的Let's Encrypt文档。

安全

安全当然是关于SSL/TLS证书的重要主题。由于这个客户端是PHP脚本,所以很可能这段代码正在Web服务器上运行。很明显,你存储在Web服务器上的私钥绝对不能从Web上访问。当客户端第一次创建密钥目录时,它会在该目录中存储一个 .htaccess 文件,拒绝所有访问者。务必确保你的密钥不能从Web上访问!如果你的私钥公开了,我绝不负责。如果发生了这种情况,最简单的解决方案是更改你的账户密钥(如上所述)或停用账户并创建一个新的账户。接下来,创建一个新的证书。

许可证

本项目遵循MIT许可证 - 有关详细信息,请参阅LICENSE 文件。