iOS 使用自签名 TLS/SSL 证书连接不起作用
<p><p>我想对 iOS 应用程序的 MITM 攻击加密和保护网络连接。由于应用程序只会连接到一台服务器,因此不需要由像 VeriSign 这样的 CA 签署证书。我想对证书进行自签名并将其与应用程序一起分发。</p>
<p>我尝试了这个,但最终得到 <code>kSecTrustResultRecoverableTrustFailure</code> 并且无法弄清楚我哪里出错了。有人可以查看它并确定问题或指出我如何调试它的方向吗?是因为我在 localhost 上使用/测试有问题吗?</p>
<p>我认为这是创建证书或设置服务器时的问题,但我不知道它是什么。我用 <code>openssl s_client</code> 对其进行了测试,它似乎可以工作,但 iOS 不接受它(见下文)。我可以接受 <code>kSecTrustResultRecoverableTrustFailure</code> 为成功,但宁愿避免它。</p>
<p><strong>创建证书</strong></p>
<p>我的 openssl.cnf。最后一行指定了 subjectAltName,应该是唯一重要的。</p>
<pre><code>[ req ]
default_bits = 2048 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = sha256 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
# Variable name Prompt string
# #---------------------- ----------------------------------
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (department, division)
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name (city, district)
stateOrProvinceName = State or Province Name (full name)
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
# Default values for the above, for consistency and less typing.
# Variable name Value
#------------------------------ ------------------------------
0.organizationName_default = The Sample Company
localityName_default = Metropolis
stateOrProvinceName_default = New York
countryName_default = US
[ server ]
basicConstraints = critical,CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
nsCertType = server
subjectAltName = IP:127.0.0.1,DNS:localhost
</code></pre>
<p>这就是我创建证书的方式。我使用 sha256,因为 md5 似乎不受支持。之后我将证书转换为 iOS 需要的 DER 格式。</p>
<pre><code>macbook:~/Documents/app/https-test/cert$ openssl req -x509 -sha256 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 356 -nodes -config openssl.cnf
Generating a 2048 bit RSA private key
..+++
............................................................+++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) :DE
State or Province Name (full name) :
Locality Name (eg, city) []:
Organization Name (eg, company) :com
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
macbook:~/Documents/app/https-test/cert$ ls
cert.der cert.pem key.pem openssl.cnf
macbook:~/Documents/app/https-test/cert$ openssl x509 -in cert.pem -outform der -out cert.der
</code></pre>
<p><strong>服务器</strong></p>
<p>服务器是接受https请求的node.js服务器。</p>
<pre><code>var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('../cert/key.pem'),
cert: fs.readFileSync('../cert/cert.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("test return\n");
}).listen(8443);
</code></pre>
<p>我用以下输出测试了这个服务器:</p>
<pre><code>macbook:~/Documents/app/https-test/server$ openssl s_client -showcerts -host localhost -port 8443 -CAfile ../cert/cert.pem
CONNECTED(00000003)
depth=0 /O=The Sample Company/L=Metropolis/ST=New York/C=US
verify return:1
---
Certificate chain
0 s:/O=The Sample Company/L=Metropolis/ST=New York/C=US
i:/O=The Sample Company/L=Metropolis/ST=New York/C=US
-----BEGIN CERTIFICATE-----
MIIDIDCCAggCCQClnXQ2tGOF1jANBgkqhkiG9w0BAQsFADBSMRswGQYDVQQKExJU
aGUgU2FtcGxlIENvbXBhbnkxEzARBgNVBAcTCk1ldHJvcG9saXMxETAPBgNVBAgT
CE5ldyBZb3JrMQswCQYDVQQGEwJVUzAeFw0xNDAyMjQwMDEwMTJaFw0xNTAyMTUw
MDEwMTJaMFIxGzAZBgNVBAoTElRoZSBTYW1wbGUgQ29tcGFueTETMBEGA1UEBxMK
TWV0cm9wb2xpczERMA8GA1UECBMITmV3IFlvcmsxCzAJBgNVBAYTAlVTMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzudBEZmW78S9EnxQzObf778qIBRf
/pUPVKSC31/8iVLM3w71GtHxI39Gt+WwAhMRRKmO+EhsFWDmQZfg3GNsws4Uj/uO
8I6Xp9rF7IWBIAZ37X2nUPD/qEU4+SFmiNi8POaXPt+5mQQLYFfun5YzpZPoiPpi
wuIkcgY8mOJlNv7Hr4AnyMtMMnscZis+ELVky5Q/mDsiamHzPPGjjKYKDMfwYj8S
yAz0GLKrcHBBm4Re++mefJU0sdapAYEliAJdTs0aBA5lxcRBzkKlFwxgsQrhtwL9
xBY+RC/PbnVWRF/YVrd7o6JvXmWOPFDlbL99v9tGGjoUyFDeLoIMaqaGmwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4IBAQAdnvu4W6GoWkAALpvpEgXBMKq2sApLHib+i8Be
+LrAS/zA1GxlMqswUBUvtGuQq88oGWC/eU3n3PvRE2tuIARg4ZSGo2/KdYfvOFYy
O7hnwdlAYirdj3XKUnomj0sVgeAjJV4xSha7aOzs9mNyLquJvewBEAvQdJnPRYfS
LwSUq5kbbiHyFWHmJnTUfLpfKj0w+LNO4Jrb0GdFs7ZWq3R0Mscig668Htue4xST
jWEh0f/ZcWLK+UVvTvpMb9DTM8oOV94EHt+slaIMEzD2hWjtLcwGfUzX5qYU450v
Kt1b40tBHRHi8ytstg4qdLlwf0NpXejcLQiW1CgNZoEIBtP+
-----END CERTIFICATE-----
---
Server certificate
subject=/O=The Sample Company/L=Metropolis/ST=New York/C=US
issuer=/O=The Sample Company/L=Metropolis/ST=New York/C=US
---
No client certificate CA names sent
---
SSL handshake has read 983 bytes and written 468 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol: TLSv1
Cipher : AES256-SHA
Session-ID: C8901BBE04CB24444E0DDEA60EB7A72A64822E652973AD1D16E27D1E1F29F828
Session-ID-ctx:
Master-Key: D143A0F58C848B0E1BCA7BDF22EEBC326F811961CC10FF3A653715A8D8F96F5825AFC6D200F334D2E1581BFECA940111
Key-Arg : None
Start Time: 1393256956
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
^C
</code></pre>
<p><strong>iOS 应用</strong></p>
<p>应用程序使用这个 NSURLConnectionDelegate <a href="https://gist.github.com/dhoerl/2051599" rel="noreferrer noopener nofollow">https://gist.github.com/dhoerl/2051599</a> </p></p>
<br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
<p><p><a href="https://gist.github.com/dhoerl/2051599" rel="noreferrer noopener nofollow">iOS code you linked to</a>期望服务器的证书在设备的受信任的根证书存储中,或者至少由受信任的根证书颁发机构签名。您收到的错误表明情况并非如此。</p>
<p>该错误意味着证书不受信任。根据定义,自签名证书不受信任,因为它不是由受信任的根证书颁发机构签名的(因此无法验证证书的签名者是否就是他们所说的那个人)。</p>
<p>如果您只想要 SSL 加密的好处而不需要保护免受 MITM 攻击,您可以通过在 NSURLConnection 委托(delegate)的 <code>didReceiveAuthenticationChallenge</code> 方法中执行以下操作来绕过服务器检查:</p>
<pre><code>- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ()
forAuthenticationChallenge:challenge];
;
}
</code></pre>
<p>请注意,这不会阻止 MITM 攻击,因为您现在允许连接到任何 SSL 主机,但如果您确实需要这种保护,则不应使用自签名证书。如果您只想要 SSL 提供的加密,自签名证书就可以了。</p>
<p>也就是说,如果您将服务器证书与您的应用程序捆绑在一起,您<em>可以</em>进行服务器身份验证 - 这称为证书固定。您需要在上面的 <code>didReceiveAuthenticationChallenge</code> 方法中添加代码,以将服务器的证书与嵌入在您的应用程序中的证书进行比较,并让它只信任该特定证书而不信任其他证书。这当然意味着如果您服务器上的证书过期或更改,您的客户端将无法再连接(直到您使用新证书重建和重新分发您的应用程序)。这也意味着,如果您的服务器的私钥被盗或泄露,您将无法撤销它并发布一个新的,并且 Bad Guys 将能够冒充您的服务器到任何尝试使用连接的客户端泄露的 key 。使用由受信任的根 CA 颁发的证书可以避免这两个问题,如果您确实需要服务器身份验证,仍然是推荐的方法。这样,您可以在需要时吊销证书,颁发新证书,一切仍然有效。</p></p>
<p style="font-size: 20px;">关于iOS 使用自签名 TLS/SSL 证书连接不起作用,我们在Stack Overflow上找到一个类似的问题:
<a href="https://stackoverflow.com/questions/21992456/" rel="noreferrer noopener nofollow" style="color: red;">
https://stackoverflow.com/questions/21992456/
</a>
</p>
页:
[1]