使用PHP和cURL防止远程服务器欺骗攻击

5

我正在编写一个PHP脚本,从远程服务器请求机密数据。 我使用cURL获取远程服务器的证书信息(请参见其输出以下内容)。

我需要检查哪些数组键以确保证书有效性,以防止被篡改?

例如,键[certinfo] [0] [Subject] [CN]可以通过自签名证书进行欺骗。

我可以只检查客户端端使用的ca-bundle文件的md5文件哈希值,但是当服务器的证书过期时,我需要相应地替换ca-bundle文件,并在PHP脚本中更新md5文件哈希值-这对我来说是不可接受的。 唯一的妥协是在不更新php脚本的情况下替换ca-bundle文件。 为此,我需要验证服务器证书的属性,这些属性将在未来证书再生期间保持不变,并且不能被恶意篡改。

print_r(curl_getinfo($ch)):

[url] => https://remoteserver.com
[content_type] => text/html
[http_code] => 200
[header_size] => 148
[request_size] => 79
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 0.374
[namelookup_time] => 0
[connect_time] => 0.062
[pretransfer_time] => 0.203
[size_upload] => 0
[size_download] => 20618
[speed_download] => 55128
[speed_upload] => 0
[download_content_length] => -1
[upload_content_length] => 0
[starttransfer_time] => 0.281
[redirect_time] => 0
[certinfo] => Array
    (
        [0] => Array
            (
                [Subject] => Array
                    (
                        [OU] => Globe Standard SSL
                        [CN] => www.remoteserver.com
                    )

                [Issuer] => Array
                    (
                        [C] => US
                        [O] => Globe Hosting, Inc.
                        [OU] => GlobeSSL DV Certification Authority
                        [CN] => GlobeSSL CA
                    )

                [Version] => 2
                [Signature Algorithm] => sha1WithRSAEncryption
                [Start date] => 2011-09-30 00:00:00 GMT
                [Expire date] => 2014-09-30 23:59:59 GMT
                [Public Key Algorithm] => rsaEncryption
                [RSA Public Key] => 2048
                [rsa(n)] => d7:c0:0b:3f:f3:3e:d6:ed:92:56:22:12:64:c1:c4:00:d7:c9:a1:1e:..cut..
                [rsa(e)] => 01:00:01:
                [X509v3 Authority Key Identifier] => keyid:C3:AB:A0:02:F0:9B:F5:66:7F:28:15:92:22:95:DB:B8:4E:D3:93:08
                [X509v3 Subject Key Identifier] => 13:1B:B2:52:14:3C:70:1C:B2:93:F1:C5:04:06:86:60:8A:D4:E5:5C
                [X509v3 Key Usage] => DigitalSignature,KeyEncipherment
                [X509v3 Basic Constraints] => CA:FALSE
                [X509v3 Extended Key Usage] => TLSWebServerAuthentication,TLSWebClientAuthentication
                [X509v3 Certificate Policies] => Policy:1.3.6.1.4.1.6449.1.2.2.27, CPS:http://www.globessl.com/docs/GlobeSSL_CPS.pdf
                [X509v3 CRL Distribution Points] => URI:http://crl.globessl.com/GlobeSSLDVCertificationAuthority.crl
                [Authority Information Access] => CAIssuers-URI:http://crt.globessl.com/GlobeSSLDVCertificationAuthority.crt, OCSP-URI:http://ocsp.globessl.com
                [X509v3 Subject Alternative Name] => DNS:www.remoteserver.com,DNS:remoteserver.com
                [Signature] => 61:38:06:d4:30:9c:14:a4:e5:1e:b2:c8:c4:..cut..
                [Cert] => -----BEGIN CERTIFICATE-----cut-----END CERTIFICATE-----

            )

        [1] => Array
            (
                [Subject] => Array
                    (
                        [C] => US
                        [O] => Globe Hosting, Inc.
                        [OU] => GlobeSSL DV Certification Authority
                        [CN] => GlobeSSL CA
                    )

                [Issuer] => Array
                    (
                        [C] => SE
                        [O] => AddTrust AB
                        [OU] => AddTrust External TTP Network
                        [CN] => AddTrust External CA Root
                    )

                [Version] => 2
                [Signature Algorithm] => sha1WithRSAEncryption
                [Start date] => 2010-06-22 00:00:00 GMT
                [Expire date] => 2020-05-30 10:48:38 GMT
                [Public Key Algorithm] => rsaEncryption
                [RSA Public Key] => 2048
                [rsa(n)] => a0:47:04:ce:a8:33:ab:..cut..
                [rsa(e)] => 01:00:01:
                [X509v3 Authority Key Identifier] => keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
                [X509v3 Subject Key Identifier] => C3:AB:A0:02:F0:9B:F5:66:7F:28:15:92:22:95:DB:B8:4E:D3:93:08
                [X509v3 Key Usage] => CertificateSign,CRLSign
                [X509v3 Basic Constraints] => CA:TRUE,pathlen:0
                [X509v3 Certificate Policies] => Policy:1.3.6.1.4.1.6449.1.2.2.27
                [X509v3 CRL Distribution Points] => URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl
                [Authority Information Access] => CAIssuers-URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c, CAIssuers-URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt, OCSP-URI:http://ocsp.usertrust.com
                [Signature] => 66:9c:13:6d:d2:7e:2c:..cut..
                [Cert] => -----BEGIN CERTIFICATE-----cut-----END CERTIFICATE-----

            )

    )

感谢您的帮助。

我们可以请一些安全专家来调查一下吗? - Christian
为您的证书制作CA,并将其添加到运行curl的机器中,这样在使用其他证书时,您将始终收到错误提示。 - zb'
除了 @eicto 的建议,Facebook 已经使用 FB SDK 实现了这一功能。你可能想要看一下... - Christian
@Christian,FB在做什么?欺骗SSL证书吗? - zb'
@eicto 不,FB SDK 中有一些证书,可能用于确保 FB 响应是有效的。 - Christian
如果CA或证书来自可信源,则可以将它们用作CA或证书,至少用于与证书颁发者通信 :) 许多公司使用自己的CA来签署其流量 :) - zb'
2个回答

1
$ch=curl_init("https://default_cert");
curl_setopt($ch, CURLOPT_CAINFO, getcwd().'mydefault.cert');
curl_setopt ($ch,CURLOPT_CERTINFO,1);
curl_setopt ($ch,CURLOPT_VERBOSE,1);
curl_exec($ch) or die;
print_r( curl_getinfo($ch) );

在这种情况下,如果mydefault.cert包含不正确的CN或证书被中间人欺骗,curl exec将失败。
mydefault.cert应该包含远程主机的证书。您必须使用可信渠道获取它(或者至少在您确定远程主机当前是受信任的情况下使用CURLOPT_SSL_VERIFYPEER,FALSE下载一次)。
一些理论: 自签名证书与非自签名证书的区别只在于 - 自签名证书是由个人为自己签发的,它有密钥和证书部分,而非自签名证书也是由你信任的某个人签发的。可以是证书中心、你最好的朋友或你的老板。如果你的朋友签发了自签名证书,并且你通过授权方式获取了证书(他将其放在磁盘上给你,或使用自己的pgp密钥签署了一封信,或者他从证书中间告诉了你20个字符),那么你可以将该证书用作CA。 证书本身是加密对的公钥密钥是该对的私钥。因此,站点执行以下操作-使用私钥以电子方式签署自己的内容,在另一端,客户端使用公钥对内容进行加密,就像使用PGP一样。
服务器到客户端的数据使用其中一种加密算法(例如ES、3DES、Blowfish、CAST128或Arcfour)进行加密,算法密钥在客户端将主机授权为受信任后由客户端初始化,该密钥由服务器的公钥(在https情况下为证书)加密。之后,客户端到服务器的数据也使用该算法进行加密,因为使用了上述方案进行密钥交换。

谷歌中获取更多信息。

您能否使用此模式来欺骗服务器发送给客户端的任何数据?


仅依赖于 ca-bundle 并不可行,因为它可以被另一个自签名证书替换。在这种情况下,您必须验证 ca-bundle 是否真实,但如果没有将文件的哈希硬编码到脚本中,则无法进行验证。 - Alexander M.
如果您已经获得了主机证书,那么它将无法被另一个证书所替换。如果您认为SSL身份验证的数学部分可以这样做,请尝试一下。 - zb'
我可以使用盐,但如果一个文件被解码,这个盐可以用于另一个文件。由于需要此代码的文件数量很高,为每个文件设置唯一的盐不是一个选项。 - Alexander M.
1
@AlexanderMalygin,你对密码学一无所知。 - zb'
简单的密钥示例:2k长度的密钥,服务器和客户端都知道。假设客户端想要将加密信息发送到服务器,它会发送一个随机字符串-salt(也是2k长度)和数据,该数据通过xor(salt,md5sum(key,salt))进行异或运算。每传输100k数据后,客户端和服务器通过更改salt重新开始握手。该算法不如ssl安全,因为密钥是固定的,但在传输过程中密钥本身永远不会被恢复,并且很难解密。如果您需要真正的安全性,请使用ssl。 - zb'

0

没有什么完全防止欺骗的方法,但是像浏览器一样,您可以尝试验证证书的真实性。关于SSL证书如何工作的一些好信息,请参考以下链接:

SSL证书是如何验证的?

现在,即使没有完全验证证书,您也可以做一些事情来确保您正在与正确的机器通信,但这需要您访问远程机器。其中最简单的事情之一是使用盐变量进行简单的握手。

例如,调用远程机器上生成唯一哈希值的文件,比如时间戳加上您选择的一个单词和您已经完成握手的次数。您的计算机将该哈希值与预期值进行匹配,并使用不同的盐执行相同的操作,将其发送回远程计算机,表示握手已完成,两台计算机都会增加计数,以便下次哈希值不同。


我有一定数量的文件,请求机密数据,这些数据必须不被欺骗。在你的情况下,如果有人解码了一个文件,他将能够使用哈希伪造其他文件的握手,因为他将知道生成此盐的逻辑。为每个文件创建唯一的盐可以解决这个问题,但这也不是一个选项。 - Alexander M.
首先,需要指出的是,有人伪造已验证的SSL证书的能力非常非常小。如果您使用自签名证书,则确实存在问题,但对于您真正需要保护且不想手动添加证书进行验证的数据来说,这并不是一个好主意。话虽如此,像SHA1这样的哈希算法的重点在于,特别是在加盐的情况下,它是无法被解密的。换句话说,除非您“提供”盐,否则第三方将无法通过“解码”逻辑来伪造握手。 - omniuni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接