工具与配置

HTTPS Tools

OpenSSL

OpenSSL 是用 C 写的一套 SSL 和 TLS 开源实现。这也就意味着人人都可以基于这个构建属于自己的认证机构,然后给自己的颁发服务器证书。不过然并卵,其证书不可在互联网上作为证书使用。这种自认证机构给自己颁发的证书,叫做自签名证书。自己给自己作证,自然是算不得数的。所以浏览器在访问这种服务器时,会显示 “ 无法确认连接安全性 ” 等警告消息。OpenSSL 在 2014 年 4 月,被爆出一个内存溢出引出的 BUG,骇客利用这点能拿到服务器很多信息,其中就包括私钥,也就使得 HTTPS 形同虚设。当时全世界大概有一百万左右的服务器有受到此漏洞的影响。由于 OpenSSL 举足轻重的作用,再加上足够致命的问题,使得这个 BUG 被形容为 “ 互联网心脏出血 ”。这是近年来互联网最严重的安全事件。

记得 OpenSSL 的 Heartbleed 漏洞才出来的时候,笔者所在的安全公司忙成了一团糟,到处帮忙修补漏洞。

Let’s Encrypt: 免费 SSL

Let’s Encrypt 是由 ISRG(Internet Security Research Group )提供的免费 SSL 项目,现由 Linux 基金会托管,他的来头很大,由 Mozilla、思科、Akamai、IdenTrust 和 EFF 等组织 发起,现在已经得到 Google、Facebook 等大公司的支持和赞助,目的就是向网站免费签发和管理证书,并且通过其自身的自动化过程,消除了购买、安装证书的复杂性,只需几行命令,就可以完成证书的生成并投入使用,甚至十几分钟就可以让自己的 http 站点华丽转变成 Https 站点。

Installation

( 1)执行以下命令

 git clone https://github.com/letsencrypt/letsencrypt
 cd letsencrypt
 ./letsencrypt-auto certonly --email xxx@xx.com

提示: 1、如果提示 git 命令无效的话,需要安装一下 GIt,直接执行命令 yum install git-all 完成安装,2、如果是 RedHat/CentOs6 系统的话,需要提前安装 EPEL( Extra Packages for Enterprise Linux ),执行命令 yum install epel-release
3、整个过程需要主机连接外网,否则会导致报以下错误

IMPORTANT NOTES:
 - The following errors were reported by the server:
   Domain: on-img.com
   Type:   urn:acme:error:connection
   Detail: Failed to connect to host for DVSNI challenge

   Domain: www.on-img.com
   Type:   urn:acme:error:connection
   Detail: Failed to connect to host for DVSNI challenge

4、Let’s encrypt 是由 python 编写的开源项目,基于 python2.7 环境,如果系统安装的是 python2.6,会提示升级。也可以执行以下命令(官方不推荐) ./letsencrypt-auto certonly –email xxx@xx.com –debug

( 2)接下来提示输入域名 多个用空格隔开 出现以下提示说明证书生成成功

使用证书

进入 /etc/letsencrypt/live/on-img.com/ 下,on-img.com 是第二部中填写的域名,到时候换成自己的域名即可。

  • cert.pem 服务器证书
  • privkey.pem 是证书私钥

如果是云服务器 + 负载均衡的话,直接添加以上证书,绑定负载均衡,直接访问 https:// xxx.com。如果是自己配置的 Nginx 的,需要以下配置:

server
{
    listen 443 ssl;   /
    server_name xxx.com;     //这里是你的域名
    index index.html index.htm index.php default.html default.htm default.php;
    root /opt/wwwroot/        //网站目录
    ssl_certificate /etc/letsencrypt/live/test.com/fullchain.pem;    //前面生成的证书,改一下里面的域名就行,不建议更换路径
    ssl_certificate_key /etc/letsencrypt/live/test.com/privkey.pem;   //前面生成的密钥,改一下里面的域名就行,不建议更换路径
    ........
}

如果是使用的 Apache 服务器,在生成证书后也需要修改一下 apache 的配置文件 /usr/local/apache/conf/httpd.conf,查找 httpd-ssl 将前面的 # 去掉。然后再执行:

cat >/usr/local/apache/conf/extra/httpd-ssl.conf<<EOF Listen 443
AddType application/x-x509-ca-cert .crt AddType application/x-pkcs7-crl .crl
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLProxyCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLHonorCipherOrder on
SSLProtocol all -SSLv2 -SSLv3 SSLProxyProtocol all -SSLv2 -SSLv3 SSLPassPhraseDialog builtin
SSLSessionCache "shmcb:/usr/local/apache/logs/ssl_scache(512000)" SSLSessionCacheTimeout 300
SSLMutex "file:/usr/local/apache/logs/ssl_mutex" EOF

并在对应 apache 虚拟主机配置文件的最后下面添加上 SSL 部分的配置文件:

<VirtualHost *:443>
    DocumentRoot /home/wwwroot/www.vpser.net   //网站目录
    ServerName www.vpser.net:443   //域名
    ServerAdmin licess@vpser.net      //邮箱
    ErrorLog "/home/wwwlogs/www.vpser.net-error_log"   //错误日志
    CustomLog "/home/wwwlogs/www.vpser.net-access_log" common    //访问日志
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/www.test.net/fullchain.pem   //改一下里面的域名就行,不建议更换路径
    SSLCertificateKeyFile /etc/letsencrypt/live/www.test.net/privkey.pem    //改一下里面的域名就行,不建议更换路径
    <Directory "/home/wwwroot/www.vpser.net">   //网站目录
        SetOutputFilter DEFLATE
        Options FollowSymLinks
        AllowOverride All
        Order allow,deny
        Allow from all
        DirectoryIndex index.html index.php
     </Directory>
</VirtualHost>

auto-sni: 自动构建基于 HTTPS 的 NodeJS 服务端

  • 安装
npm install auto-sni
  • 创建服务器
var createServer = require("auto-sni");

var server = createServer({
    email: ..., // Emailed when certificates expire.
    agreeTos: true, // Required for letsencrypt.
    debug: true, // Add console messages and uses staging LetsEncrypt server. (Disable in production)
    domains: ["mysite.com", ["test.com", "www.test.com"]], // List of accepted domain names. (You can use nested arrays to register bundles with LE).
    forceSSL: true, // Make this false to disable auto http->https redirects (default true).
    ports: {
        http: 80, // Optionally override the default http port.
        https: 443 // // Optionally override the default https port.
    }
});

// Server is a "https.createServer" instance.server.once("listening", ()=> {
    console.log("We are ready to go.");
});

//使用Express
var createServer = require("auto-sni");
var express      = require("express");
var app          = express();

app.get("/test", ...);

createServer({ email: ..., agreeTos: true }, app);

SSL Configuration Generator

现在很多用户使用的还是低版本的浏览器,它们对于 SSL/TLS 协议支持的也不是很好,因此怎么为服务器选定一个正确的 HTTPS 也比较麻烦,幸好 Mozilla 提供了一个在线生成配置的工具,很是不错:

SSL Server Test

在你正确配置了你的站点之后,非常推荐使用SSL Labs这个在线测试工具来检查下你站点到底配置的是否安全。

HTTPS Configuration

Apache

<VirtualHost *:443>
    ...
    SSLEngine on
    SSLCertificateFile      /path/to/signed_certificate_followed_by_intermediate_certs
    SSLCertificateKeyFile   /path/to/private/key
    SSLCACertificateFile    /path/to/all_ca_certs


    # HSTS (mod_headers is required) (15768000 seconds = 6 months)
    Header always set Strict-Transport-Security "max-age=15768000"
    ...
</VirtualHost>

# intermediate configuration, tweak to your needs
SSLProtocol             all -SSLv3
SSLCipherSuite          ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder     on
SSLCompression          off
SSLSessionTickets       off

# OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling          on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache        shmcb:/var/run/ocsp(128000)

Nginx

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /path/to/signed_cert_plus_intermediates;
    ssl_certificate_key /path/to/private_key;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /path/to/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

    resolver <IP DNS resolver>;

    ....
}

Lighttpd

$SERVER["socket"] == ":443" {
    protocol     = "https://"
    ssl.engine   = "enable"
    ssl.disable-client-renegotiation = "enable"

    # pemfile is cert+privkey, ca-file is the intermediate chain in one file
    ssl.pemfile               = "/path/to/signed_cert_plus_private_key.pem"
    ssl.ca-file               = "/path/to/intermediate_certificate.pem"
    # for DH/DHE ciphers, dhparam should be >= 2048-bit
    ssl.dh-file               = "/path/to/dhparam.pem"
    # ECDH/ECDHE ciphers curve strength (see `openssl ecparam -list_curves`)
    ssl.ec-curve              = "secp384r1"
    # Compression is by default off at compile-time, but use if needed
    # ssl.use-compression     = "disable"

    # Environment flag for HTTPS enabled
    setenv.add-environment = (
        "HTTPS" => "on"
    )

    # intermediate configuration, tweak to your needs
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
    ssl.honor-cipher-order    = "enable"
    ssl.cipher-list           = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"

    # HSTS(15768000 seconds = 6 months)
    setenv.add-response-header  = (
        "Strict-Transport-Security" => "max-age=15768000;"
    )

    ...
}

HAProxy

global
    # set default parameters to the intermediate configuration
    tune.ssl.default-dh-param 2048
    ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
    ssl-default-bind-options no-sslv3 no-tls-tickets
    ssl-default-server-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
    ssl-default-server-options no-sslv3 no-tls-tickets

frontend ft_test
    mode    http
    bind    :443 ssl crt /path/to/<cert+privkey+intermediate+dhparam>
    bind    :80
    redirect scheme https code 301 if !{ ssl_fc }

    # HSTS (15768000 seconds = 6 months)
    rspadd  Strict-Transport-Security:\ max-age=15768000

AWS ELB

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "Example ELB with Mozilla recommended ciphersuite",
  "Parameters": {
    "SSLCertificateId": {
      "Description": "The ARN of the SSL certificate to use",
      "Type": "String",
      "AllowedPattern": "^arn:[^:]*:[^:]*:[^:]*:[^:]*:.*$",
      "ConstraintDescription": "SSL Certificate ID must be a valid ARN. http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns"
    }
  },
  "Resources": {
    "ExampleELB": {
      "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties": {
        "Listeners": [
          {
            "LoadBalancerPort": "443",
            "InstancePort": "80",
            "PolicyNames": ["Mozilla-intermediate-2015-03"],
            "SSLCertificateId": {
              "Ref": "SSLCertificateId"
            },
            "Protocol": "HTTPS"
          }
        ],
        "AvailabilityZones": {
          "Fn::GetAZs": ""
        },
        "Policies": [
          {
            "PolicyName": "Mozilla-intermediate-2015-03",
            "PolicyType": "SSLNegotiationPolicyType",
            "Attributes": [
              {
                "Name": "Protocol-TLSv1",
                "Value": true
              },
              {
                "Name": "Protocol-TLSv1.1",
                "Value": true
              },
              {
                "Name": "Protocol-TLSv1.2",
                "Value": true
              },
              {
                "Name": "Server-Defined-Cipher-Order",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-CHACHA20-POLY1305",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-CHACHA20-POLY1305",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES128-GCM-SHA256",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES128-GCM-SHA256",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES256-GCM-SHA384",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES256-GCM-SHA384",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES128-GCM-SHA256",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES256-GCM-SHA384",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES128-SHA256",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES128-SHA256",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES128-SHA",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES256-SHA384",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES128-SHA",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES256-SHA384",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-AES256-SHA",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-AES256-SHA",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES128-SHA256",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES128-SHA",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES256-SHA256",
                "Value": true
              },
              {
                "Name": "DHE-RSA-AES256-SHA",
                "Value": true
              },
              {
                "Name": "ECDHE-ECDSA-DES-CBC3-SHA",
                "Value": true
              },
              {
                "Name": "ECDHE-RSA-DES-CBC3-SHA",
                "Value": true
              },
              {
                "Name": "EDH-RSA-DES-CBC3-SHA",
                "Value": true
              },
              {
                "Name": "AES128-GCM-SHA256",
                "Value": true
              },
              {
                "Name": "AES256-GCM-SHA384",
                "Value": true
              },
              {
                "Name": "AES128-SHA256",
                "Value": true
              },
              {
                "Name": "AES256-SHA256",
                "Value": true
              },
              {
                "Name": "AES128-SHA",
                "Value": true
              },
              {
                "Name": "AES256-SHA",
                "Value": true
              },
              {
                "Name": "DES-CBC3-SHA",
                "Value": true
              }
            ]
          }
        ]
      }
    }
  },
  "Outputs": {
    "ELBDNSName": {
      "Description": "DNS entry point to the stack (all ELBs)",
      "Value": {
        "Fn::GetAtt": ["ExampleELB", "DNSName"]
      }
    }
  }
}
下一页