mlocati/spf-lib

解析、构建和验证 SPF (发送者策略框架) DNS 记录

资助包维护!
mlocati
其他

3.1.2 2022-09-09 09:05 UTC

This package is auto-updated.

Last update: 2024-08-28 23:38:04 UTC


README

Tests Code Coverage

SPF (发送者策略框架) 库

此 PHP 库允许您

  • 从域名获取 SPF 记录
  • 解码和验证 SPF 记录
  • 创建 TXT 记录的值
  • 检查域名和 IP 地址是否满足 SPF 记录

实现基于 RFC 7208

据我所知,这是唯一通过 Open SPF 测试套件(针对 RFC 7208) 的 PHP 库。

此库支持从 PHP 7.1 到 8.3 的任何 PHP 版本。

关于 SPF 的简要介绍

以下是 SPF 协议目的的非常简化的简要描述。

当电子邮件客户端联系电子邮件服务器以发送电子邮件消息时,电子邮件服务器有这些信息

  1. 发送电子邮件的电子邮件客户端的 IP 地址
  2. 电子邮件客户端在 SMTP 交付开始时指定的域名(在 HELO/EHLO SMTP 命令之后)
  3. 发送者电子邮件地址(在 MAIL FROM SMTP 命令中指定)

电子邮件服务器可以使用 SPF 协议来确定客户端是否被允许或被拒绝使用指定的域名发送电子邮件(HELO/EHLO 域和/或 MAIL FROM 电子邮件地址中 @ 之后)。

这是通过查询要检查的域名(域)的 SPF DNS 记录来完成的,这些记录可以告诉服务器客户端是否被允许/不允许/很可能不被允许发送电子邮件。

您可以使用此 PHP 库构建、验证和检查 SPF 记录。

安装

您可以使用 Composer 安装此库

composer require mlocati/spf-lib

用法

验证域名和 IP 地址

假设电子邮件客户端具有 IP 地址 1.2.3.4,使用 HELO/EHLO SMTP 命令指定 helo.domain,并在 MAIL FROM 电子邮件地址中指定 [email protected]

这些数据由 SPFLib\Check\Environment 类表示:您可以使用以下方式创建它

$environment = new \SPFLib\Check\Environment(`1.2.3.4`, `helo.domain`, `[email protected]`);

要检查 SPF 记录,您可以使用 SPFLib\Checker

$checker = new \SPFLib\Checker();
$checkResult = $checker->check($environment);

默认情况下,check() 方法检查 HELO/EHLOMAIL FROM 域(如果都可用且不同)。您可以通过将 \SPFLib\Checker::FLAG_CHECK_HELODOMAIN\SPFLib\Checker::FLAG_CHECK_MAILFROADDRESS 作为 check() 方法的第二个参数指定,仅检查其中一个。否则,您可以在相关的 Environment 构造函数中指定一个空字符串(例如:new Environment($ip, $domain) 将仅检查 HELO/EHLO 域,new Environment($ip, '', $mailFromAddress) 将仅检查 MAIL FROM 电子邮件地址的域名)。

$checkResultSPFLib\Term\Mechanism\Result 的一个实例,它提供

  • 检查结果($checkResult->getCode()),这是在 RFC 中指定的 值之一
  • 如果有的话,提供结果的 SPF 机制($checkResult->getMatchedMechanism()
  • 失败描述,如果由 SPF 记录提供($checkResult->getFailExplanation()
  • 检查过程中的可选相关消息($checkResult->getMessages()

因此,最简单的例子是

use SPFLib\Checker;
use SPFLib\Check\Environment;

$checker = new Checker();
$checkResult = $checker->check(new Environment('127.0.0.1', 'gmail.com'));
echo $checkResult->getCode();

它将输出

softfail

从域名检索 SPF 记录

SPF 记录由零个或多个术语组成。每个术语可以是机制或修饰符。

此库允许您检查它们

$decoder = new \SPFLib\Decoder();
try {
    $record = $decoder->getRecordFromDomain('example.com');
} catch (\SPFLib\Exception $x) {
    // Problems retrieving the SPF record from example.com,
    // or problems decoding it
    return;
}
if ($record === null) {
    // SPF record not found for example.com
    return;
}
// List all terms (that is, mechanisms and modifiers)
foreach ($record->getTerms() as $term) {
    // do your stuff
}
// List all mechanisms
foreach ($record->getMechanisms() as $mechanism) {
    // do your stuff
}
// List all modifiers
foreach ($record->getModifiers() as $modifiers) {
    // do your stuff
}

请注意

从 TXT DNS 记录的值解码 SPF 记录

$txtRecord = 'v=spf1 mx a -all';
$decoder = new \SPFLib\Decoder();
try {
    $record = $decoder->getRecordFromTXT($txtRecord);
} catch (\SPFLib\Exception $x) {
    // Problems decoding $txtRecord (it's malformed).
    return;
}
if ($record === null) {
    // $txtRecord is not an SPF record
    return;
}

创建 SPF 记录的值

use SPFLib\Term\Mechanism;

$record = new \SPFLib\Record('example.org');
$record
    ->addTerm(new Mechanism\MxMechanism(Mechanism::QUALIFIER_PASS))
    ->addTerm(new Mechanism\IncludeMechanism(Mechanism::QUALIFIER_PASS, 'example.com'))
    ->addTerm(new Mechanism\AllMechanism(Mechanism::QUALIFIER_FAIL))
;
echo (string) $record;

输出

v=spf1 mx include:example.com -all

检查 SPF 记录的问题

$spf = 'v=spf1 all redirect=example1.org redirect=example2.org ptr:foo.bar mx include=example3.org exp=test.%{p}';
$record = (new \SPFLib\Decoder())->getRecordFromTXT($spf);
$issues = (new \SPFLib\SemanticValidator())->validate($record);
foreach ($issues as $issue) {
    echo (string) $issue, "\n";
}

输出

[warning] 'all' should be the last mechanism (any other mechanism will be ignored)
[warning] The 'redirect' modifier will be ignored since there's a 'all' mechanism
[notice] The 'ptr' mechanism shouldn't be used because it's slow, resource intensive, and not very reliable
[notice] The term 'exp=test.%{p}' contains the macro-letter 'p' that shouldn't be used because it's slow, resource intensive, and not very reliable
[notice] The modifiers ('redirect=example1.org', 'redirect=example2.org') should be after all the mechanisms
[fatal] The 'redirect' modifier is present more than once (2 times)
[notice] The 'include=example3.org' modifier is unknown

请注意,validate 方法返回的数组中的每个项目都是 SPFLib\Semantic\Issue 类的实例。

在现实世界中检查 SPF 记录的问题

SemanticValidator 只在 SPF 记录中查找问题,而不检查 include(或重定向到)记录。

为了检查 SPF 记录及其所有引用的记录,您可以使用 OnlineSemanticValidator

$validator = new \SPFLib\OnlineSemanticValidator();
// Check an online domain
$issues = $validator->validateDomain('example.org');
// Check a raw SPF record
$issues = $validator->validateRawRecord('v=spf1 include:_sfp.example.org -all');
// Check an SPFLib\Record instance ($record in this case)
$issues = $validator->validateRecord($record);

这些方法的结果是 SPFLib\Semantic\OnlineIssue 实例的数组,这些实例与离线 SemanticValidator 返回的 SPFLib\Semantic\Issue 实例非常相似。

您真的想表示感谢吗?

您可以通过提供 每月咖啡一次性咖啡 来感谢我😉