11.10小节完成

This commit is contained in:
XiongNeng
2015-11-25 12:02:08 +08:00
parent 169d19de8e
commit d3419df867

View File

@@ -5,18 +5,18 @@
----------
问题
----------
You want to implement a network service involving sockets where servers and clients
authenticate themselves and encrypt the transmitted data using SSL.
你想实现一个基于sockets的网络服务客户端和服务器通过SSL协议认证并加密传输的数据。
|
----------
解决方案
----------
The ssl module provides support for adding SSL to low-level socket connections. In
particular, the ssl.wrap_socket() function takes an existing socket and wraps an SSL
layer around it. For example, heres an example of a simple echo server that presents a
server certificate to connecting clients:
``ssl`` 模块能为底层socket连接添加SSL的支持。
``ssl.wrap_socket()`` 函数接受一个已存在的socket作为参数并使用SSL层来包装它。
例如,下面是一个简单的应答服务器,能在服务器端为所有客户端连接做认证。
.. code-block:: python
from socket import socket, AF_INET, SOCK_STREAM
import ssl
@@ -55,15 +55,16 @@ def echo_server(address):
echo_server(('', 20000))
Heres an interactive session that shows how to connect to the server as a client. The
client requires the server to present its certificate and verifies it:
下面我们演示一个客户端连接服务器的交互例子。客户端会请求服务器来认证并确认连接:
.. code-block:: python
>>> from socket import socket, AF_INET, SOCK_STREAM
>>> import ssl
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s_ssl = ssl.wrap_socket(s,
... cert_reqs=ssl.CERT_REQUIRED,
... ca_certs = 'server_cert.pem')
cert_reqs=ssl.CERT_REQUIRED,
ca_certs = 'server_cert.pem')
>>> s_ssl.connect(('localhost', 20000))
>>> s_ssl.send(b'Hello World?')
12
@@ -71,12 +72,13 @@ client requires the server to present its certificate and verifies it:
b'Hello World?'
>>>
The problem with all of this low-level socket hacking is that it doesnt play well with
existing network services already implemented in the standard library. For example,
most server code (HTTP, XML-RPC, etc.) is actually based on the socketserver library.
Client code is also implemented at a higher level. It is possible to add SSL to existing
services, but a slightly different approach is needed.
First, for servers, SSL can be added through the use of a mixin class like this:
这种直接处理底层socket方式有个问题就是它不能很好的跟标准库中已存在的网络服务兼容。
例如绝大部分服务器代码HTTP、XML-RPC等实际上是基于 ``socketserver`` 库的。
客户端代码在一个较高层上实现。我们需要另外一种稍微不同的方式来将SSL添加到已存在的服务中
首先对于服务器而言可以通过像下面这样使用一个mixin类来添加SSL
.. code-block:: python
import ssl
@@ -105,8 +107,9 @@ class SSLMixin:
server_side = True)
return client_ssl, addr
To use this mixin class, you can mix it with other server classes. For example, heres an
example of defining an XML-RPC server that operates over SSL:
为了使用这个mixin类你可以将它跟其他服务器类混合。例如下面是定义一个基于SSL的XML-RPC服务器例子
.. code-block:: python
# XML-RPC server with SSL
@@ -115,7 +118,7 @@ from xmlrpc.server import SimpleXMLRPCServer
class SSLSimpleXMLRPCServer(SSLMixin, SimpleXMLRPCServer):
pass
Heres the XML-RPC server from Recipe 11.6 modified only slightly to use SSL:
Here's the XML-RPC server from Recipe 11.6 modified only slightly to use SSL:
import ssl
from xmlrpc.server import SimpleXMLRPCServer
@@ -158,8 +161,10 @@ if __name__ == '__main__':
certfile=CERTFILE),
kvserv.serve_forever()
To use this server, you can connect using the normal xmlrpc.client module. Just spec
ify a https: in the URL. For example:
使用这个服务器时,你可以使用普通的 ``xmlrpc.client`` 模块来连接它。
只需要在URL中指定 ``https:`` 即可,例如:
.. code-block:: python
>>> from xmlrpc.client import ServerProxy
>>> s = ServerProxy('https://localhost:15000', allow_none=True)
@@ -176,11 +181,11 @@ ify a https: in the URL. For example:
False
>>>
One complicated issue with SSL clients is performing extra steps to verify the server
certificate or to present a server with client credentials (such as a client certificate).
Unfortunately, there seems to be no standardized way to accomplish this, so research is
often required. However, here is an example of how to set up a secure XML-RPC con
nection that verifies the servers certificate:
对于SSL客户端来讲一个比较复杂的问题是如何确认服务器证书或为服务器提供客户端认证比如客户端证书
不幸的是,暂时还没有一个标准方法来解决这个问题,需要自己去研究。
不过下面给出一个例子用来建立一个安全的XML-RPC连接来确认服务器证书
.. code-block:: python
from xmlrpc.client import SafeTransport, ServerProxy
import ssl
@@ -208,9 +213,11 @@ s = ServerProxy('https://localhost:15000',
transport=VerifyCertSafeTransport('server_cert.pem'),
allow_none=True)
As shown, the server presents a certificate to the client and the client verifies it. This
verification can go both directions. If the server wants to verify the client, change the
server startup to the following:
服务器将证书发送给客户端,客户端来确认它的合法性。这种确认可以是相互的。
如果服务器想要确认客户端,可以将服务器启动代码修改如下:
.. code-block:: python
if __name__ == '__main__':
KEYFILE='server_key.pem' # Private key of the server
CERTFILE='server_cert.pem' # Server certificate
@@ -224,8 +231,9 @@ if __name__ == '__main__':
)
kvserv.serve_forever()
To make the XML-RPC client present its certificates, change the ServerProxy initiali
zation to this:
为了让XML-RPC客户端发送证书修改 ``ServerProxy`` 的初始化代码如下:
.. code-block:: python
# Create the client proxy
s = ServerProxy('https://localhost:15000',
@@ -239,19 +247,16 @@ s = ServerProxy('https://localhost:15000',
----------
讨论
----------
Getting this recipe to work will test your system configuration skills and understanding
of SSL. Perhaps the biggest challenge is simply getting the initial configuration of keys,
certificates, and other matters in order.
To clarify whats required, each endpoint of an SSL connection typically has a private
key and a signed certificate file. The certificate file contains the public key and is pre
sented to the remote peer on each connection. For public servers, certificates are nor
mally signed by a certificate authority such as Verisign, Equifax, or similar organization
(something that costs money). To verify server certificates, clients maintain a file con
taining the certificates of trusted certificate authorities. For example, web browsers
maintain certificates corresponding to the major certificate authorities and use them to
verify the integrity of certificates presented by web servers during HTTPS connections.
For the purposes of this recipe, you can create whats known as a self-signed certificate.
Heres how you do it:
试着去运行本节的代码能测试你的系统配置能力和理解SSL。
可能最大的挑战是如何一步步的获取初始配置key、证书和其他所需依赖。
我解释下到底需要啥每一个SSL连接终端一般都会有一个私钥和一个签名证书文件。
这个证书包含了公钥并在每一次连接的时候都会发送给对方。
对于公共服务器它们的证书通常是被权威证书机构比如Verisign、Equifax或其他类似机构需要付费的签名过的。
为了确认服务器签名,客户端回保存一份包含了信任授权机构的证书列表文件。
例如web浏览器保存了主要的认证机构的证书并使用它来为每一个HTTPS连接确认证书的合法性。
对本小节示例而言,只是为了测试,我们可以创建自签名的证书,下面是主要步骤:
bash % openssl req -new -x509 -days 365 -nodes -out server_cert.pem \
-keyout server_key.pem
@@ -260,6 +265,7 @@ Generating a 1024 bit RSA private key
...++++++
writing new private key to 'server_key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
@@ -277,12 +283,8 @@ Common Name (eg, YOUR name) []:localhost
Email Address []:
bash %
When creating the certificate, the values for the various fields are often arbitrary. How
ever, the “Common Name” field often contains the DNS hostname of servers. If youre
just testing things out on your own machine, use “localhost.” Otherwise, use the domain
name of the machine thats going to run the server.
As a result of this configuration, you will have a server_key.pem file that contains the
private key. It looks like this:
在创建证书的时候各个值的设定可以是任意的但是”Common Name“的值通常要包含服务器的DNS主机名。
如果你只是在本机测试那么就使用”localhost“否则使用服务器的域名。
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCZrCNLoEyAKF+f9UNcFaz5Osa6jf7qkbUl8si5xQrY3ZYC7juu
@@ -300,7 +302,7 @@ private key. It looks like this:
CHZXdJ3XQ6qUmNxNn7iJ7S/LDawo1QfWkCfD9FYoxBlg
-----END RSA PRIVATE KEY-----
The server certificate in server_cert.pem looks similar:
服务器证书文件server_cert.pem内容类似下面这样
-----BEGIN CERTIFICATE-----
MIIC+DCCAmGgAwIBAgIJAPMd+vi45js3MA0GCSqGSIb3DQEBBQUAMFwxCzAJBgNV
@@ -322,18 +324,16 @@ The server certificate in server_cert.pem looks similar:
D3vvcW5lAnCCC80P6rXy7d7hTeFu5EYKtRGXNvVNd/06NALGDflrrOwxF3Y=
-----END CERTIFICATE-----
In server-related code, both the private key and certificate file will be presented to the
various SSL-related wrapping functions. The certificate is what gets presented to clients.
The private key should be protected and remains on the server.
In client-related code, a special file of valid certificate authorities needs to be maintained
to verify the servers certificate. If you have no such file, then at the very least, you can
put a copy of the servers certificate on the client machine and use that as a means for
verification. During connection, the server will present its certificate, and then youll
use the stored certificate you already have to verify that its correct.
Servers can also elect to verify the identity of clients. To do that, clients need to have
their own private key and certificate key. The server would also need to maintain a file
of trusted certificate authorities for verifying the client certificates.
If you intend to add SSL support to a network service for real, this recipe really only
gives a small taste of how to set it up. You will definitely want to consult the documen
tation for more of the finer points. Be prepared to spend a significant amount of time
experimenting with it to get things to work.
在服务器端代码中私钥和证书文件会被传给SSL相关的包装函数。证书来自于客户端
私钥应该在保存在服务器中,并加以安全保护。
在客户端代码中,需要保存一个合法证书授权文件来确认服务器证书。
如果你没有这个文件,你可以在客户端复制一份服务器的证书并使用它来确认。
连接建立后,服务器会提供它的证书,然后你就能使用已经保存的证书来确认它是否正确。
服务器也能选择是否要确认客户端的身份。如果要这样做的话,客户端需要有自己的私钥和认证文件。
服务器也需要保存一个被信任证书授权文件来确认客户端证书。
如果你要在真实环境中为你的网络服务加上SSL的支持这小节只是一个入门介绍而已。
你还应该参考其他的文档,做好花费不少时间来测试它正常工作的准备。反正,就是得慢慢折腾吧~ ^_^