Total Pageviews

Wednesday, 6 March 2013

使用stunnel做双向认证

Using stunnel With Bilateral Authentication


Read Me First

Important: This page was written in 2002. I was contacted a couple of years ago by the author of stunnel, indicating that stunnel has evolved so much since then that as far as stunnel information goes, this page is essentially worse than useless. I don't use stunnel anymore so am unable to update it. I should probably remove this page entirely, but I can't quite bring myself to do it. So please don't rely on the information on this page.

Background

stunnel provides "drop-in" SSL-secured connectivity between two hosts. It is most often used to retroactively secure an existing application when encryption and/or authentication were not part of the original design.
When neither the client nor the server support SSL encapsulation of a connection, stunnel can be used on both sides of the connection.
In its default configuration, stunnel does not perform authentication; it merely encrypts the channel without verifying the endpoints.
This document describes how to set up stunnel to use signed certificates to perform bilateral authentication. Under this scheme, both the client and the server provide sufficient credentials (in the form of SSL certificates signed by a mutually acceptable authority) to establish their identity.

Document Conventions

Black Text represents output from the software or prompts for information that will appear.
Green Text represents commands or information that (at least the first time) can be entered exactly as shown.
Red Text represents commands or information that must be customized to the particular situation before being entered. For example, WWWI should be changed to the name of your own organization.

Stunnel Security Limitations

stunnel has two significant limitations that affect its ability to perform bilateral authentication. The first is that there is no provision for encrypted keys. The second is that stunnel does not perform browser-style checking of the CN name field against the hostname of the connection. In combination, these limitations mean that if someone can access an stunnel key, they will not need a passphrase to decode it and that they can use that key from any connected host without regard for its hostname or IP address.
It is therefore vital to ensure that systems with stunnel keys are carefully secured and that the keys are stored with the most restrictive possible permissions.
This is not a strictly speaking a limitation of stunnel, but rather a difficulty HTTP-over-SSL has traditionally worked around by allowing the web server to prompt for a passphrase on startup, and by using browsers that compare the common name (CN) of a server's certificate to the hostname. Perhaps a future version of stunnel will offer an option to enable similar functionality.

Creating Certificates

  1. Create a non-encrypted private key for the client: YourPrompt&ht; openssl genrsa -out client.key 1024
    Generating RSA private key, 1024 bit long modulus
    ......................++++++
    ...........................................++++++
    e is 65537 (0x10001)
    YourPrompt>
  2. Create a certificate signature request for the new client key: YourPrompt> openssl req -new -key client.key -out client.csr
    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) [AU]:US
    State or Province Name (full name) [Some-State]:Texas
    Locality Name (eg, city) []:Montgomery
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:WWWI
    Organizational Unit Name (eg, section) []:WWWI Stunnel Services
    Common Name (eg, YOUR name) []:WWWI Client
    Email Address []:.

    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:.
    An optional company name []:.

  3. Get the client.csr signed by your certificate authority. If you are self-signing certificates, the command would be similar to: YourPrompt> .../path/to/mod_ssl/pkg.contrib/sign.sh client.csr
    CA signing: client.csr -> client.crt:
    Using configuration from ca.config
    Enter PEM pass phrase:CAKeyPassPhrase
    Check that the request matches the signature
    Signature ok
    The Subjects Distinguished Name is as follows
    countryName :PRINTABLE:'US'
    stateOrProvinceName :PRINTABLE:'Texas'
    localityName :PRINTABLE:'Montgomery'
    organizationName :PRINTABLE:'WWWI'
    organizationalUnitName:PRINTABLE:'WWWI Stunnel Services'
    commonName :PRINTABLE:'WWWI Client'
    Certificate is to be certified until Feb 22 22:22:22 2003 GMT (365 days)
    Sign the certificate? [y/n]:y


    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated
    CA verifying: client.crt <-> CA cert
    client.crt: OK

  4. Construct an stunnel-client.pem file from the key and certificate as follows: -----BEGIN RSA PRIVATE KEY-----
    [encoded key]
    -----END RSA PRIVATE KEY-----
    -----BEGIN CERTIFICATE-----
    [encoded certificate]
    -----END CERTIFICATE-----

    There are no extra blank lines or extraneous text needed in this file.
  5. Copy the CA certificate (ca.crt) to stunnel-auth.pem.
  6. Install both stunnel-client.pem and stunnel-auth.pem on the client in the appropriate stunnel directory (the one specified by --with-pem-dir during configure, where the default stunnel.pem is installed).
  7. Repeat steps 1 through 5 for the server (server.key, server.csr, server.crt, stunnel-server.pem). The stunnel-auth.pem file will be the same for the server.

Running Stunnel

For this example, we will use mysql-3.23.X, which includes both client and server pieces and does not support native SSL connections.
  1. Start mysql on the server machine. YourPrompt> nohup mysqld --bind-address=127.0.0.1 --user=mysql &

    Binding to the localhost IP address (127.0.0.1) ensures that other systems cannot gain unencrypted/unauthenticated access to MySQL.
  2. Start stunnel on the server machine. YourPrompt> stunnel -A /usr/local/stunnel/stunnel-auth.pem -v 2 -p /usr/local/stunnel/stunnel-server.pem -d server.example.com:3307 -r localhost:3306
  3. Start stunnel on the client machine. YourPrompt> stunnel -A /usr/local/stunnel/stunnel-auth.pem -v 2 -p /usr/local/stunnel/stunnel-client.pem -c -d localhost:3306 -r server.example.com:3307
  4. Test the mysql client on the client machine. YourPrompt> mysql -h 127.0.0.1
    Welcome to the MySQL monitor. Commands end with ; or \g.
    Your MySQL connection id is 6615 to server version: 3.23.49

    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

    mysql> \q
    Bye

    If problems occur with the mysql connection, check the stunnel log files or use -f to run stunnel in the foreground on each machine. It will provide information about any errors that occur in the certificate exchange process.
    It is important to remember that from the MySQL server, all connections will appear to be originating from localhost. MySQL's internal user/host/password tables must be configured appropriately. Also, the SSL certificate exchange process can be relatively time consuming compared to an SQL query. Therefore, connection pooling becomes more important as a tool to improve performance when security is implemented in this fashion.

Increasing Security

It is possible to further increase security by requiring stunnel to compare the certificate presented by its peer against a stored list of acceptable certificates. To take advantage of this feature:
  1. Change the '-v 2' parameter of each stunnel command line to '-v 3'.
  2. Add each system's certificate to the stunnel-auth.pem file of each system it will connect to.
This is particularly appropriate if the certificate authority being used also serves any other purpose that should not imply the ability to access the resource being secured.

Thanks

Particular thanks go to the creators of stunnel, OpenSSL and MySQL for making such great products。

from http://web.archive.org/web/20050920025232/http://software.wwwi.com:80/ssl/stunnel.shtml
(http://software.wheelhouse.org/ssl/stunnel.shtml)

These documents were made possible by information gathered from the following sources. Thanks to:
-------


stunnel双向证书认证


stunnel 双向证书认证:防止没授权的客户端连接stunnel服务器,防止客户端连接假的服务器
stunnel官方的说明是:(客户端)检查服务器端证书是为了防止中间人攻击;(服务器端)检查客户端证书是为了严格控制客户端的访问。
  1. Server authentication prevents Man-In-The-Middle (MITM) attacks on the encryption protocol.
  2. Client authentication allows for restricting access for individual clients (access control).

stunnel安全说明

stunnel有四种证书检查配置,用verify选项控制。
  1. Do not Verify Certificates 不检查证书,默认值
    If no verify argument is given, then stunnel will ignore any certificates offered and will allow all connections.
  2. verify = 1 如果证书存在则检查证书
    Verify the certificate, if present.
  3. verify = 2 每个SSL连接要求检查证书
    Require and verify certificates
    Stunnel will require and verify certificates for every SSL connection. If no certificate or an invalid certificate is presented, then it will drop the connection.
  4. verify = 3 依据本地安装的证书检查证书
    Require and verify certificates against locally installed certificates.
  5. verify = 4 忽略CA chain,只验证peer certificate
    ignore CA chain and only verify peer certificate
verify配置2 3 4的时候,都会开启双向证书认证,自行选择。这里选择verify = 3
stunnel服务端的防盗连安全机制是:在服务器CAfile里配置客户端的证书,并设置verify = 3,服务器端检查客户端证书,证书不在CAfile列表的客户端则会被断开连接。
同样,为了避免客户端连接到假的服务端,则需要配置verify = 3,并把服务端的公钥证书放在客户端侧的CAfile里。

第一步 生成证书

生成两个证书,一个服务端的stunnel_s.pem,一个客户端的stunnel_c.pem,有效期设置长一点,10000天,时间可以自行调整。
$openssl req -new -x509 -days 10000 -nodes -out stunnel_c.pem -keyout stunnel_c.pem
$openssl req -new -x509 -days 10000 -nodes -out stunnel_s.pem -keyout stunnel_s.pem

第二步 服务器端stunnel.conf

将证书拷贝到/etc/stunnel目录,设置权限400(文件拥有者只读,其他人不可查看).
$sudo cp stunnel_s.pem /etc/stunnel/
$sudo cp stunnel_c.pem /etc/stunnel/
$sudo chmod 400 /etc/stunnel/*.pem
创建stunnel.conf文件,内容如下,拷贝到/etc/stunnel/目录。对外端口是8445,加密的是cow HTTP proxy的7777端口连接,根据情况自行修改。如果要调试打开output选项。cow是个HTTP代理,智能分流值得推荐。
;fips=no
client = no
sslVersion=all

chroot = /var/lib/stunnel4/
setuid = root
setgid = root

pid = /stunnel4.open.pid
;output = /stunnel.open.log
cert = /etc/stunnel/stunnel_s.pem
key = /etc/stunnel/stunnel_s.pem

[open]
accept = 8445
connect = 7777

verify = 3
CAfile = /etc/stunnel/stunnel_c.pem
重启stunnel服务器
$sudo service  stunnel4  restart

第三步 客户端stunnel.conf

我的客户端运行在windows系统,所以下面的配置是windows上stunnel验证的。其他系统配置类似,自行配置验证。
stunnel_c.pemstunnel_s.pem(存放在客户端的stunnel_s.pem最好删除证书里BEGIN PRIVATE KEY私钥部分,只保留BEGIN CERTIFICATE公钥部分)拷贝到stunnel安装目录,修改stunnel.conf文件,配置如下。stunnel_ip是服务器端stunnel的IP,端口是8084,浏览器配置127.0.0.1:8084 HTTP代理。如果要换其他端口自行修改。
fips=no
client = yes
sslVersion = all
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
socket = l:SO_LINGER=1:1
socket = r:SO_LINGER=1:1

[fastssl]
accept = 127.0.0.1:8084
connect = stunnel_ip:8445

verify = 3
CAfile = stunnel_s.pem

cert = stunnel_c.pem
key = stunnel_c.pem
如果客户端连接stunnel服务器端需要HTTP代理(公司网络),fastssl部分这样配置
[fastssl]
accept = 127.0.0.1:8084
connect = proxy.company.com:80
protocol = connect
protocolHost = stunnel_ip:8445

pem证书安全存放说明

pem证书是文本文件,里面BEGIN PRIVATE KEYEND PRIVATE KEY是私钥部分,BEGIN CERTIFICATEEND CERTIFICATE是公钥部分。certkey配置完整的pem,而CAfile里只包含对方的公钥部分即可,即服务端CAfile是客户端的公钥,客户端CAfile是服务端的公钥。遵循这样原则,客户端的私钥只放客户端,服务端的私钥只放服务端,而公钥是可以多处存放的。
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9WC13gg9WCRX
...
kPpWg2PAANRi5Bmr9ScvBISSYQ==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIJANBMqvP0YuV4MA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD
...
o5tKoL9GcMhyjDoD9GCMfP6fY5DwPqhhqFTsPd47DzEdQ8amxPMn5kR/w/xk
-----END CERTIFICATE-----
多个公钥证书保存在一个CAfile里,这样排列存放。官方说明Where do I put all these certificates?
-----BEGIN CERTIFICATE-----
certificate #1 data here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
certificate #2 data here
-----END CERTIFICATE-----