我一直在试图找到一种在PHP(oa1
)中验证DNS记录的方法,但没有成功。
我可以使用此库验证整个域,但不能验证单个记录:https://github.com/metaregistrar/php-dnssec-validator
此外,该库只允许验证一小部分TLD。
有没有另一个图书馆可以为我处理这个问题,或者我应该研究其他什么?
我还发现:http://www.phpclasses.org/package/9031-PHP-Validate-DNSSEC-keys-and-calculate-the-DS-record.html
但我不知道如何在验证功能中使用密钥。
救命!
更新
所以,我最终使用了这个。。。
exec('host -t RRSIG ' . $domain, $output);
返回RRSIG,或不返回RRSIG时,麻烦最小。
PHP引擎支持一组固定的DNS记录类型,所有这些类型都由dns_get_record
的type
参数定义。您可以通过查找实现DNS查询的引擎代码来仔细检查此列表。
不幸的是,DNSSEC记录都不在该预定义列表中。因此,您需要依赖库或外部工具。
我会使用Net_DNS2
,因为它支持许多DNSSEC RR。示例:
$google = new 'Net_DNS2_Resolver(['nameservers' => ['8.8.8.8', '8.8.4.4']]);
$google->dnssec = true;
try {
$result = $google->query('kyhwana.org', 'SSHFP');
} catch('Net_DNS2_Exception $ex) {
die($ex->getMessage());
}
foreach ($result->answer as $answer) {
if ($answer instanceof 'Net_DNS2_RR_SSHFP) {
printf(
'%s %d %s %s %d %d %s' . PHP_EOL,
$answer->name,
$answer->ttl,
$answer->class,
$answer->type,
$answer->algorithm,
$answer->fp_type,
$answer->fingerprint
);
} else if ($answer instanceof 'Net_DNS2_RR_RRSIG) {
printf('Signed by %s: %s' . PHP_EOL, $answer->signname, $answer->signature);
}
}
此外:如果您的域使用ECDSA算法或SHA-256指纹(如上面的示例),那么您需要最新的Net_DNS2代码来修复问题#39。
我还没有实现代码,但在我看来,使用php来验证签名本身是一个错误。在强制使用DNSSEC的本地服务器上使用类似unbound的本地递归解析程序。
然后在php中使用PEAR模块Net_DNS2查找感兴趣域的RRSIG记录。结果应该告诉你该记录的责任区域。
在该区域中查找DNSKEY记录。如果存在,则查找DS记录。
DS记录将来自父区域(例如,异常电子邮件),如果存在,则表示该区域存在DNSSEC。
如果该区域存在DNSSEC,那么如果本地递归名称服务器强制使用DNSSEC,则该区域的所有结果都是有效的。
我相信Net_DNS2使用
r = new Net_DNS2_Resolver(array('nameservers' => array('127.0.0,1')));
r->dnssec = true;
如果DNSSEC处于活动状态(由来自父区域的DS记录指示),则Net_DNS2也将验证结果。但是使用递归解析器(最好是在Web服务器上)来强制DNSSEC可能是最安全的。
确保递归解析器没有监听公共接口,这样它就不会被用于反射放大攻击。
有着相同的目标(在PHP中验证DNSSEC),我最终得到了:
exec("drill -k root.keys -TDQ $domain SOA | grep -v '^;;'", $output);
这是在执行完整自上而下的DNSSEC验证。
你需要根密钥,你可以检索:
unbound-anchor # NB: on FreeBSD, use local-unbound-anchor for "base" version
或者";手动":
dig . dnskey > root.keys
要确认记录已完全DNSSEC验证,请检查exec输出的最后一行:
- [S] self-sig OK这不令人满意,可能父区域中没有填充区域键
- [B] 伪造的
- [T] trusted这意味着一切都很好