Nginx 配置 ECC RSA 双证书
Config Nginx for parallel ECC and RSA Certificate
先决条件
Nginx 1.11.0 以上
OpenSSL 1.0.2 以上
申请证书
首先申请 ECC 证书,这个不多说,很多方法都可以,大部分 CA 现在也都可以签署。生成 CSR 的命令是:
openssl ecparam -out 证书名.key -name prime256v1 -genkey && openssl req -new -key 证书名.key -nodes -out 证书名.csr
拿到证书之后,还是像之前一样将中级 CA 拼接在证书后面,得到给 Nginx 使用的 domain-cert.crt
配置 Nginx
首先是将两个证书链都加入 Nginx 的配置文件:
ssl_certificate example.com.rsa.crt; ssl_certificate_key example.com.rsa.key; ssl_certificate example.com.ecdsa.crt; ssl_certificate_key example.com.ecdsa.key;
如果要使用 CT 的话有两种方法:
1. 将两个证书的 CT 信息放到同一目录,并做如下设置:
ssl_ct on; ssl_ct_static_scts /path/to/sct/dir;
这样 Nginx CT 模块会自动在这个目录下查找相应证书的 CT 信息并发送
2. 可以单独配置每个证书的 CT 文件:
ssl_ct on; ssl_certificate example.com.rsa.crt; ssl_certificate_key example.com.rsa.key; ssl_ct_static_scts xample.com.rsa.scts; ssl_certificate example.com.ecdsa.crt; ssl_certificate_key example.com.ecdsa.key; ssl_ct_static_scts example.com.ecdsa.scts;
然后问题来了。很多盆友这么配置之后可能发现用 Chrome 之类的明明支持 ECC 的浏览器却并没有用 ECC 证书。这是为什么呢?
问题就出在 ssl_ciphers 这个配置项上面。
如果我们用各种网上推荐的配置,需要注意顺序问题。以 Cloud Flare 的配置为例:
#https://github.com/cloudflare/sslconfig/blob/master/conf ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on;
注意到这里面的算法都是优先使用 RSA 的,所以服务器和浏览器协商出来的一定是 RSA ,这就导致 Nginx 会自动发送 RSA 证书链给浏览器。
这里可以用 openssl 验证一下:
# openssl ciphers -V 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5' | column -t 0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 0xC0,0x13 - ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 0xC0,0x09 - ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 0x00,0x9C - AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD 0x00,0x3C - AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 0x00,0x2F - AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 0xC0,0x14 - ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 0xC0,0x0A - ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 0x00,0x9D - AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD 0x00,0x3D - AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 0x00,0x35 - AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 0xC0,0x12 - ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1 0xC0,0x08 - ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1 0x00,0x0A - DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1
会看到第一个选择就是使用 RSA,而不是椭圆曲线 ECDSA。
再来验证一下 Mozilla 给出的配置:
# openssl ciphers -V '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' | column -t 0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD 0x00,0x9E - DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD 0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 0xC0,0x09 - ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 0xC0,0x13 - ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 0xC0,0x0A - ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 0xC0,0x14 - ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 0x00,0x67 - DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 0x00,0x33 - DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1 0x00,0x6B - DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 0x00,0x39 - DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 0xC0,0x08 - ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1 0xC0,0x12 - ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1 0x00,0x16 - EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Au=RSA Enc=3DES(168) Mac=SHA1 0x00,0x9C - AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD 0x00,0x9D - AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD 0x00,0x3C - AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 0x00,0x3D - AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 0x00,0x2F - AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 0x00,0x35 - AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 0x00,0x0A - DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1
在这份配置中可以看到,每种套件中使用椭圆曲线部分都被排在了 RSA 前面,所以能尽量协商出支持椭圆曲线的算法。
或者我们还可以更激进一些:
# openssl ciphers -V 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK' | column -t 0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 0xC0,0x09 - ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 0xC0,0x0A - ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD 0x00,0x9E - DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD 0x00,0xA2 - DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(128) Mac=AEAD 0x00,0xA3 - DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(256) Mac=AEAD 0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD 0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 0xC0,0x13 - ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 0xC0,0x14 - ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 0x00,0x67 - DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 0x00,0x33 - DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1 0x00,0x40 - DHE-DSS-AES128-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(128) Mac=SHA256 0x00,0x6B - DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 0x00,0x38 - DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1 0x00,0x39 - DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 0x00,0x9C - AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD 0x00,0x9D - AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD 0x00,0x3C - AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 0x00,0x3D - AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 0x00,0x2F - AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 0x00,0x35 - AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 0x00,0x6A - DHE-DSS-AES256-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(256) Mac=SHA256 0xC0,0x32 - ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD 0xC0,0x2E - ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD 0xC0,0x2A - ECDH-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256) Mac=SHA384 0xC0,0x26 - ECDH-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256) Mac=SHA384 0xC0,0x0F - ECDH-RSA-AES256-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(256) Mac=SHA1 0xC0,0x05 - ECDH-ECDSA-AES256-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256) Mac=SHA1 0x00,0x32 - DHE-DSS-AES128-SHA SSLv3 Kx=DH Au=DSS Enc=AES(128) Mac=SHA1 0xC0,0x31 - ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD 0xC0,0x2D - ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD 0xC0,0x29 - ECDH-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128) Mac=SHA256 0xC0,0x25 - ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128) Mac=SHA256 0xC0,0x0E - ECDH-RSA-AES128-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(128) Mac=SHA1 0xC0,0x04 - ECDH-ECDSA-AES128-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128) Mac=SHA1 0x00,0x88 - DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(256) Mac=SHA1 0x00,0x87 - DHE-DSS-CAMELLIA256-SHA SSLv3 Kx=DH Au=DSS Enc=Camellia(256) Mac=SHA1 0x00,0x84 - CAMELLIA256-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(256) Mac=SHA1 0x00,0x45 - DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(128) Mac=SHA1 0x00,0x44 - DHE-DSS-CAMELLIA128-SHA SSLv3 Kx=DH Au=DSS Enc=Camellia(128) Mac=SHA1 0x00,0x41 - CAMELLIA128-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(128) Mac=SHA1
可以看到在这份配置中,我几乎将所有的支持椭圆曲线的套件都提到了最前面,来加大协商出支持椭圆曲线算法的套件的可能性。
综上,推荐的配置如下:
ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5'; 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_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
三者任选其一即可。
参考:
https://imququ.com/post/ecc-certificate.html
https://www.zeroling.com/nginx-kai-qi-https-shuang-zheng-shu-zhi-nan/
https://n4l.pw/nginx-dual-certificates.html
https://imququ.com/post/certificate-transparency.html
https://seryo.net/use-ecc-algorithms-issued-a-certificate-request-file.Seryo
Apache HttpClient 使用代理服务器 Proxy 的一个小坑
今天在调试一个用 HttpClient 写的 Demo 的时候遇到了一个问题:
org.apache.http.impl.execchain.RetryExec execute INFO: I/O exception (org.apache.http.conn.UnsupportedSchemeException) caught when processing request to {tls}->http://proxyserver:port->https://servername:443: http protocol is not supported
也就是在通过 HTTP Proxy 进行 HTTPS 连接的时候,HttpClient 报了一个不支持 HTTP 协议。查了一下发现问题在于我使用 HttpClient 的方法。
由于我在使用 HttpClient 的时候是手动创建的 Registry
// Create a registry of custom connection socket factories for supported // protocol schemes. RegistrysocketFactoryRegistry = RegistryBuilder. create() .register("https", sslsf) .build(); // Create a connection manager with custom configuration. PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
需要修改为:
// Create a registry of custom connection socket factories for supported // protocol schemes. RegistrysocketFactoryRegistry = RegistryBuilder. create() .register("https", sslsf) .register("http", PlainConnectionSocketFactory.INSTANCE) .build(); // Create a connection manager with custom configuration. PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
加的这句保证了这个ConnectionSocketFactory 也可以处理 HTTP 协议,从而避免这个问题。
MySQL 隐式转化整理
前几天在微博上看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下。希望对大家有所帮助。
当我们对不同类型的值进行比较的时候,为了使得这些数值「可比较」(也可以称为类型的兼容性),MySQL会做一些隐式转化(Implicit type conversion)。比如下面的例子:
mysql> SELECT 1+'1'; -> 2 mysql> SELECT CONCAT(2,' test'); -> '2 test'
很明显,上面的SQL语句的执行过程中就出现了隐式转化。并且从结果们可以判断出,第一条SQL中,将字符串的“1”转换为数字1,而在第二条的SQL中,将数字2转换为字符串“2”。
MySQL也提供了CAST()
函数。我们可以使用它明确的把数值转换为字符串。当使用CONCA()
函数的时候,也可能会出现隐式转化,因为它希望的参数为字符串形式,但是如果我们传递的不是字符串呢:
mysql> SELECT 38.8, CAST(38.8 AS CHAR); -> 38.8, '38.8' mysql> SELECT 38.8, CONCAT(38.8); -> 38.8, '38.8'
隐式转化规则
官方文档中关于隐式转化的规则是如下描述的:
If one or both arguments are
NULL
, the result of the comparison isNULL
, except for theNULL
-safe<=>
equality comparison operator. ForNULL <=> NULL
, the result is true. No conversion is needed.
- If both arguments in a comparison operation are strings, they are compared as strings.
- If both arguments are integers, they are compared as integers.
- Hexadecimal values are treated as binary strings if not compared to a number.
- If one of the arguments is a
TIMESTAMP
orDATETIME
column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments toIN()
! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when usingBETWEEN
with date or time values, useCAST()
to explicitly convert the values to the desired data type.A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to aDATETIME
value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands asDATETIME
values, useCAST()
to explicitly convert the subquery value toDATETIME
.- If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.
- In all other cases, the arguments are compared as floating-point (real) numbers.
翻译为中文就是:
- 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换
- 两个参数都是字符串,会按照字符串来比较,不做类型转换
- 两个参数都是整数,按照整数来比较,不做类型转换
- 十六进制的值和非数字做比较时,会被当做二进制串
- 有一个参数是
TIMESTAMP
或DATETIME
,并且另外一个参数是常量
,常量会被转换为timestamp
- 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
- 所有其他情况下,两个参数都会被转换为浮点数再进行比较
注意点
安全问题:假如 password 类型为字符串,查询条件为 int 0 则会匹配上。
mysql> select * from test; +----+-------+-----------+ | id | name | password | +----+-------+-----------+ | 1 | test1 | password1 | | 2 | test2 | password2 | +----+-------+-----------+ 2 rows in set (0.00 sec) mysql> select * from test where name = 'test1' and password = 0; +----+-------+-----------+ | id | name | password | +----+-------+-----------+ | 1 | test1 | password1 | +----+-------+-----------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +---------+------+-----------------------------------------------+ | Level | Code | Message | +---------+------+-----------------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: 'password1' | +---------+------+-----------------------------------------------+ 1 row in set (0.00 sec)
相信上面的例子,一些机灵的同学可以发现其实上面的例子也可以做sql注入。
假设网站的登录那块做的比较挫,使用下面的方式:
SELECT * FROM users WHERE username = '$_POST["username"]' AND password = '$_POST["password"]'
如果username输入的是 a’ OR 1=’1 ,那么password随便输入,这样就生成了下面的查询:
SELECT * FROM users WHERE username = 'a' OR 1='1' AND password = 'anyvalue'
就有可能登录系统。其实如果攻击者看过了这篇文章,那么就可以利用隐式转化来进行登录了。如下:
mysql> select * from test; +----+-------+-----------+ | id | name | password | +----+-------+-----------+ | 1 | test1 | password1 | | 2 | test2 | password2 | | 3 | aaa | aaaa | | 4 | 55aaa | 55aaaa | +----+-------+-----------+ 4 rows in set (0.00 sec) mysql> select * from test where name = 'a' + '55'; +----+-------+----------+ | id | name | password | +----+-------+----------+ | 4 | 55aaa | 55aaaa | +----+-------+----------+ 1 row in set, 5 warnings (0.00 sec)
之所以出现上述的原因是因为:
mysql> select '55aaa' = 55; +--------------+ | '55aaa' = 55 | +--------------+ | 1 | +--------------+ 1 row in set, 1 warning (0.00 sec) mysql> select 'a' + '55'; +------------+ | 'a' + '55' | +------------+ | 55 | +------------+ 1 row in set, 1 warning (0.00 sec)
下面通过一些例子来复习一下上面的转换规则:
mysql> select 1+1; +-----+ | 1+1 | +-----+ | 2 | +-----+ 1 row in set (0.00 sec) mysql> select 'aa' + 1; +----------+ | 'aa' + 1 | +----------+ | 1 | +----------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +---------+------+----------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: 'aa' | +---------+------+----------------------------------------+ 1 row in set (0.00 sec)
把字符串“aa”和1进行求和,得到1,因为“aa”和数字1的类型不同,MySQL官方文档告诉我们:
When an operator is used with operands of different types, type conversion occurs to make the operands compatible.
查看warnings可以看到隐式转化把字符串转为了double类型。但是因为字符串是非数字型的,所以就会被转换为0,因此最终计算的是0+1=1
上面的例子是类型不同,所以出现了隐式转化,那么如果我们使用相同类型的值进行运算呢?
mysql> select 'a' + 'b'; +-----------+ | 'a' + 'b' | +-----------+ | 0 | +-----------+ 1 row in set, 2 warnings (0.00 sec) mysql> show warnings; +---------+------+---------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: 'a' | | Warning | 1292 | Truncated incorrect DOUBLE value: 'b' | +---------+------+---------------------------------------+ 2 rows in set (0.00 sec)
是不是有点郁闷呢?
之所以出现这种情况,是因为+
为算术操作符arithmetic operator 这样就可以解释为什么a
和b
都转换为double了。因为转换之后其实就是:0+0=0
了。
再看一个例子:
mysql> select 'a'+'b'='c'; +-------------+ | 'a'+'b'='c' | +-------------+ | 1 | +-------------+ 1 row in set, 3 warnings (0.00 sec) mysql> show warnings; +---------+------+---------------------------------------+ | Level | Code | Message | +---------+------+---------------------------------------+ | Warning | 1292 | Truncated incorrect DOUBLE value: 'a' | | Warning | 1292 | Truncated incorrect DOUBLE value: 'b' | | Warning | 1292 | Truncated incorrect DOUBLE value: 'c' | +---------+------+---------------------------------------+ 3 rows in set (0.00 sec)
现在就看也很好的理解上面的例子了吧。a+b=c结果为1,1在MySQL中可以理解为TRUE,因为’a’+’b’的结果为0,c也会隐式转化为0,因此比较其实是:0=0也就是true,也就是1.
第二个需要注意点就是防止多查询或者删除数据
mysql> select * from test; +----+-------+-----------+ | id | name | password | +----+-------+-----------+ | 1 | test1 | password1 | | 2 | test2 | password2 | | 3 | aaa | aaaa | | 4 | 55aaa | 55aaaa | | 5 | 1212 | aaa | | 6 | 1212a | aaa | +----+-------+-----------+ 6 rows in set (0.00 sec) mysql> select * from test where name = 1212; +----+-------+----------+ | id | name | password | +----+-------+----------+ | 5 | 1212 | aaa | | 6 | 1212a | aaa | +----+-------+----------+ 2 rows in set, 5 warnings (0.00 sec) mysql> select * from test where name = '1212'; +----+------+----------+ | id | name | password | +----+------+----------+ | 5 | 1212 | aaa | +----+------+----------+ 1 row in set (0.00 sec)
上面的例子本意是查询id为5的那一条记录,结果把id为6的那一条也查询出来了。我想说明什么情况呢?有时候我们的数据库表中的一些列是varchar类型,但是存储的值为‘1123’这种的纯数字的字符串值,一些同学写sql的时候又不习惯加引号。这样当进行select,update或者delete的时候就可能会多操作一些数据。所以应该加引号的地方别忘记了。
关于字符串转数字的一些说明
mysql> select 'a' = 0; +---------+ | 'a' = 0 | +---------+ | 1 | +---------+ 1 row in set, 1 warning (0.00 sec) mysql> select '1a' = 1; +----------+ | '1a' = 1 | +----------+ | 1 | +----------+ 1 row in set, 1 warning (0.00 sec) mysql> select '1a1b' = 1; +------------+ | '1a1b' = 1 | +------------+ | 1 | +------------+ 1 row in set, 1 warning (0.00 sec) mysql> select '1a2b3' = 1; +-------------+ | '1a2b3' = 1 | +-------------+ | 1 | +-------------+ 1 row in set, 1 warning (0.00 sec) mysql> select 'a1b2c3' = 0; +--------------+ | 'a1b2c3' = 0 | +--------------+ | 1 | +--------------+ 1 row in set, 1 warning (0.00 sec)
从上面的例子可以看出,当把字符串转为数字的时候,其实是从左边开始处理的。
- 如果字符串的第一个字符就是非数字的字符,那么转换为数字就是0
- 如果字符串以数字开头
- 如果字符串中都是数字,那么转换为数字就是整个字符串对应的数字
- 如果字符串中存在非数字,那么转换为的数字就是开头的那些数字对应的值
如果你有其他更好的例子,或者被隐式转化坑过的情况,欢迎分享。
参考资料
- http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html
- https://blog.eood.cn/mysql_params
- http://dev.mysql.com/doc/refman/5.7/en/type-conversion.html
转自:http://www.cnblogs.com/rollenholt/p/5442825.html
退出当前 Bash Shell 并不保存历史的 5 种方法
某些时候我们希望在退出 Bash Shell 的时候不要保存执行命令的历史记录,那么可以用以下几种方法来实现:
先说两个不影响以前的历史记录的方法:
1. 修改 HISTFILE 变量
unset HISTFILE && exit
2. 直接 Kill 当前 Shell
kill -9 $$
下面三个方法会清除所有的记录:
3. 清除历史记录并退出
history -c && exit
4. 设置历史记录保存数量为 0 条并退出
HISTSIZE=0 && exit
5. 删除历史记录文件并修改 HISTFILE 变量
rm -f $HISTFILE && unset HISTFILE && exit
如果你想每次都自动执行这些命令,可以在将对应的指令添加到 ~/.bash_logout 文件中,或者使用 alisa 功能。
译自:http://www.if-not-true-then-false.com/2010/quit-bash-shell-without-saving-bash-history/
搭建需要身份认证的 Squid 代理
1. 安装 Squid
sudo apt-get update sudo apt-get upgrade sudo apt-get install squid
或者
yum install squid
2. 配置 HTTP 代理
注意,在 Ubuntu 下配置文件的默认位置可能是 /etc/squid3/,下面均用 CentOS 的 /etc/squid/ 举例,请自行替换。
基础设置:
首先设置允许访问该代理的 IP 列表:
# /etc/squid/squid.conf acl client src 12.34.56.78 #客户端1 IP 地址 acl client src 21.43.56.78 #客户端2 IP 地址 ... http_access allow client
注意这几行要加在配置文件原有的
http_access deny all
之前,不然不会生效。
然后重启 squid 服务,让配置生效。
service squid restart #CentOS service squid3 restart #Ubuntu
注意!非常不建议使用 http_access allow all,你的代理一定会被别人扫到用来干坏事!
高级验证:
如果想使用用户名密码来做权限控制,则需要进行一些额外的配置:
首先,我们需要安装 htpasswd,这个工具集成在 apache httpd 的 tools 里面
apt-get install apache2-utils yum install httpd-tools
安装完成之后执行 htpasswd,如果没有提示找不到命令,则说明安装成功。
接下来创建保存用户名密码的文件:
touch /etc/squid/squid_passwd chown squid /etc/squid/squid_passwd
注意授权的时候要弄清楚 squid 运行时的用户名,一般是 squid 或者 proxy。
然后执行:
htpasswd /etc/squid/squid_passwd username New password: Re-type new password: Adding password for user username
注意把 username 换成你想要的用户名。
如果想要继续添加用户,请多次执行这条命令。
接下来修改 /etc/squid/squid.conf 文件,在 http_access deny all 之前加上下面几句:
auth_param basic program /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd auth_param basic children 5 auth_param basic realm Squid proxy-caching web server auth_param basic credentialsttl 2 hours auth_param basic casesensitive off
acl ncsa_users proxy_auth REQUIRED
http_access allow ncsa_users
这里要注意,如果你的系统是 64 位的,那么 /usr/lib/squid/ncsa_auth 这个模块的地址应该是 /usr/lib64/squid/ncsa_auth。设置之前建议用这个命令来检查一下:
dpkg -L squid | grep ncsa_auth
rpm -ql squid | grep ncsa_auth
下面说说这几个选项的含义:
auth_param basic program /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd : 指定密码文件和用来验证密码的程序
auth_param basic children 5 : 鉴权进程的数量
auth_param basic realm Squid proxy-caching web server : 用户输入用户名密码时看到的提示信息
auth_param basic credentialsttl 2 hours : 用户名和密码的缓存时间,也就是说同一个用户名多久会调用 ncsa_auth 一次。
auth_param basic casesensitive off : 用户名是否需要匹配大小写
acl ncsa_users proxy_auth REQUIRED : 所有成功鉴权的用户都归于 ncsa_users 组
http_access allow ncsa_users : 允许 ncsa_users 组的用户使用 Proxy
配置完成后重启 Squid 就可以啦!
3. 匿名
默认情况下,Squid 会添加很多和客户信息相关的 HTTP 头,如 X-Forwarded-For 这类。如果想要做到高度匿名,需要将这些头去掉。在 squid.conf 里面添加如下的配置:
forwarded_for off request_header_access Allow allow all request_header_access Authorization allow all request_header_access WWW-Authenticate allow all request_header_access Proxy-Authorization allow all request_header_access Proxy-Authenticate allow all request_header_access Cache-Control allow all request_header_access Content-Encoding allow all request_header_access Content-Length allow all request_header_access Content-Type allow all request_header_access Date allow all request_header_access Expires allow all request_header_access Host allow all request_header_access If-Modified-Since allow all request_header_access Last-Modified allow all request_header_access Location allow all request_header_access Pragma allow all request_header_access Accept allow all request_header_access Accept-Charset allow all request_header_access Accept-Encoding allow all request_header_access Accept-Language allow all request_header_access Content-Language allow all request_header_access Mime-Version allow all request_header_access Retry-After allow all request_header_access Title allow all request_header_access Connection allow all request_header_access Proxy-Connection allow all request_header_access User-Agent allow all request_header_access Cookie allow all request_header_access All deny all
然后重启就可以啦!
默认情况下,Squid 会把主机相关的信息发送出去,并显示在错误页面。加上下面两句去掉这些信息:
# add this to /etc/squid/squid.conf visible_hostname mybogusproxyhostname.local # and while we are at it stop squid blabbing about it's version aswell httpd_suppress_version_string on
最后说一个小坑,apache httpd 2.2 版本和 2.4 版本的 htpasswd 生成的密码文件格式是不一样的。只有 2.2 版本的能用。
如果按照教程设置成功以后发现用户名密码死活不对,文件权限也没有问题的话,那就要看一下是不是 htpasswd 的问题了。
直接输入 /usr/lib/squid/ncsa_auth /etc/squid/squid_passwd 然后输入 username passwd 可以手动运行一下 ncsa_auth 程序,看看是否是密码文件的问题。
如果提示 OK 那么说明没有问题,提示 ERR Wrong password 则说明要么是密码输错了,要么是密码文件的格式有问题。
PS:放出一个最简单的 PAC 文件,用来做代理的按需访问:
function FindProxyForURL(url, host) { if(ProxyDomain(url, host)) { return "PROXY 1.2.3.4:8080"; } else { return "DIRECT"; } } function ProxyDomain(url, host) { if( shExpMatch(host, "*.maoxian.de") || shExpMatch(host, "*.baidu.com") ) { return true } return false; }
PS:
编译安装的时候要注意一点,从 3.2 开始,编译使用的参数有了一点小变化,原先的:
--enable-auth="basic" --enable-baisc-auth-#helpers="NCSA"
变成了
--enable-auth \ --enable-auth-basic=NCSA \
同时配置文件里的 /usr/lib/squid/ncsa_auth 模块可能会变成 /usr/bin/basic_ncsa_auth ,需要注意。
https://www.linode.com/docs/networking/squid/squid-http-proxy-ubuntu-12-04
常用 openssl 命令
The Most Common OpenSSL Commands
One of the most versatile SSL tools is OpenSSL which is an open source implementation of the SSL protocol. There are versions of OpenSSL for nearly every platform, including Windows, Linux, and Mac OS X. OpenSSL is commonly used to create the CSR and private key for many different platforms, including Apache. However, it also has hundreds of different functions that allow you to view the details of a CSR or certificate, compare an MD5 hash of the certificate and private key (to make sure they match), verify that a certificate is installed properly on any website, and convert the certificate to a different format. A compiled version of OpenSSL for Windows can be found here.
If you don’t want to bother with OpenSSL, you can do many of the same things with our SSL Certificate Tools. Below, we have listed the most common OpenSSL commands and their usage:
General OpenSSL Commands
These commands allow you to generate CSRs, Certificates, Private Keys and do other miscellaneous tasks.
- Generate a new private key and Certificate Signing Request
openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key
- Generate a self-signed certificate (see How to Create and Install an Apache Self Signed Certificate for more info)
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt
- Generate a certificate signing request (CSR) for an existing private key
openssl req -out CSR.csr -key privateKey.key -new
- Generate a certificate signing request based on an existing certificate
openssl x509 -x509toreq -in certificate.crt -out CSR.csr -signkey privateKey.key
- Remove a passphrase from a private key
openssl rsa -in privateKey.pem -out newPrivateKey.pem
Checking Using OpenSSL
If you need to check the information within a Certificate, CSR or Private Key, use these commands. You can also check CSRs and check certificates using our online tools.
- Check a Certificate Signing Request (CSR)
openssl req -text -noout -verify -in CSR.csr
- Check a private key
openssl rsa -in privateKey.key -check
- Check a certificate
openssl x509 -in certificate.crt -text -noout
- Check a PKCS#12 file (.pfx or .p12)
openssl pkcs12 -info -in keyStore.p12
Debugging Using OpenSSL
If you are receiving an error that the private doesn’t match the certificate or that a certificate that you installed to a site is not trusted, try one of these commands. If you are trying to verify that an SSL certificate is installed correctly, be sure to check out the SSL Checker.
- Check an MD5 hash of the public key to ensure that it matches with what is in a CSR or private key
openssl x509 -noout -modulus -in certificate.crt | openssl md5 openssl rsa -noout -modulus -in privateKey.key | openssl md5 openssl req -noout -modulus -in CSR.csr | openssl md5
- Check an SSL connection. All the certificates (including Intermediates) should be displayed
openssl s_client -connect www.paypal.com:443
Converting Using OpenSSL
These commands allow you to convert certificates and keys to different formats to make them compatible with specific types of servers or software. For example, you can convert a normal PEM file that would work with Apache to a PFX (PKCS#12) file and use it with Tomcat or IIS. Use our SSL Converter to convert certificates without messing with OpenSSL.
- Convert a DER file (.crt .cer .der) to PEM
openssl x509 -inform der -in certificate.cer -out certificate.pem
- Convert a PEM file to DER
openssl x509 -outform der -in certificate.pem -out certificate.der
- Convert a PKCS#12 file (.pfx .p12) containing a private key and certificates to PEM
openssl pkcs12 -in keyStore.pfx -out keyStore.pem -nodes
You can add -nocerts to only output the private key or add -nokeys to only output the certificates.
- Convert a PEM certificate file and a private key to PKCS#12 (.pfx .p12)
openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt
Originally posted on Sun Jan 13, 2008
https://www.sslshopper.com/article-most-common-openssl-commands.html
dd 常用命令汇总
生成指定大小的文件
dd if=/dev/urandom of=sample.txt bs=1G count=1 dd if=/dev/urandom of=sample.txt bs=64M count=16 dd if=/dev/random of=sample.txt bs=1G count=1 dd if=/dev/random of=sample.txt bs=64M count=16
测试磁盘的读写速度
一般常用的能查到的测试磁盘读写速度的命令是下面几个:
dd bs=1M count=256 if=/dev/zero of=test dd bs=1M count=256 if=/dev/zero of=test; sync dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
但是实际上,这几个的效果并不完全相同:
-
dd bs=1M count=256 if=/dev/zero of=test
The default behaviour ofdd
is to not “sync” (i.e. not ask the OS to completely write the data to disk beforedd
exiting). The above command will just commit your 256 MB of data into a RAM buffer (write cache) – this will be really fast and it will show you the hugely inflated benchmark result right away. However, the server in the background is still busy, continuing to write out data from the RAM cache to disk.
dd 的默认行为是不做任何“同步”操作(也就是说,不要求操作系统在 dd 终止前完整的将数据写入磁盘。)上面那个命令只会给你分配 256M 的 RAM 缓存(写缓存)- 这个操作是非常快的,会告诉你非常夸张的测试觉果。但是实际上,服务器本身还在后台繁忙的进行写入操作,来将你刚刚写入 RAM 缓存的数据同步到磁盘。# dd bs=1M count=256 if=/dev/zero of=test 256+0 records in 256+0 records out 268435456 bytes (268 MB) copied, 0.217855 s, 1.2 GB/s
-
dd bs=1M count=256 if=/dev/zero of=test; sync
Absolutely identical to the previous case, as anyone who understands how *nix shell works should surely know that adding a; sync
does not affect the operation of previous command in any way, because it is executed independently, after the first command completes. So your (inflated) MB/sec value is already printed on screen while thatsync
is only preparing to be executed.
跟上一个命令完全相同。任何知道 *nix shell 如何运作的人都一定知道只是加一个 ; sync 并不会影响签名一条命令,因为这两条命令是完全分开执行的,添加的 sync 是在 dd 执行结束之后才会执行的。所以当你看到夸张的 MB/s 的值的时候,sync 命令才刚刚开始准备执行。# dd bs=1M count=256 if=/dev/zero of=test; sync 256+0 records in 256+0 records out 268435456 bytes (268 MB) copied, 0.225096 s, 1.2 GB/s (Waiting for sync) #
-
dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync
This tellsdd
to require a complete “sync” once, right before it exits. So it commits the whole 256 MB of data, then tells the operating system: “OK, now ensure this is completely on disk”, only then measures the total time it took to do all that and calculates the benchmark result.
这条指令告诉 dd 在退出之前必须要等待“同步”结束。所以该命令先是创建了 256M 的数据,然后告诉系统:“现在确认这些数据已经写到了磁盘上”,然后才开始停止计时并计算测试的结果。# dd bs=1M count=256 if=/dev/zero of=test conv=fdatasync 256+0 records in 256+0 records out 268435456 bytes (268 MB) copied, 1.54606 s, 174 MB/s
-
dd bs=1M count=256 if=/dev/zero of=test oflag=dsync
Heredd
will ask for completely synchronous output to disk, i.e. ensure that its write requests don’t even return until the submitted data is on disk. In the above example, this will mean sync’ing once per megabyte, or 256 times in total. It will be the slowest mode, as the write cache is basically unused at all in this case.
这条命令 dd 会要求完全同步写入磁盘,也就是说,任何一个写入请求在数据完全保存到磁盘之前都不会返回。在上面这条命令里,这代表 dd 将会每 1MB 同步一次,或者说一共要同步256次。所以这是最慢模式,因为这种情况下基本上完全没有使用缓存。# dd bs=1M count=256 if=/dev/zero of=test oflag=dsync 256+0 records in 256+0 records out 268435456 bytes (268 MB) copied, 2.40251 s, 112 MB/s
当然有时候连续执行第三条和第四条命令,第四条并不比第三条慢。这可能是由于其他应用的 IO 占用导致的。
所以,一般情况下推荐使用第三条命令来进行测试,尽可能快的得到尽可能准确的结果。
原文地址:https://romanrm.net/dd-benchmark
Nginx 配置 403 Error Page
今天遇到一个很有意思的问题,就是给 Nginx 配置 403 时候的错误页面。因为这台 Nginx 针对访问 IP 做了一些限制,所以需要给无权限访问的用户展示一个友好的界面。
一开始我的设置是这么写的:
... allow 10.0.0.0/24; allow 192.168.0.0/24; deny 1.2.3.4; deny 2.3.4.5; error_page 403 /403.html; ...
可是实际使用发现,无论如何 Nginx 展示的都是内置 Hard Code 进去的那个 404 页面,并不是我想让他展示的友好的界面。
在排除了各种文件权限之类的错误之后,我 Google 了一下发现,这个真正的原因在于前面配置的 deny 不仅 deny 掉了正常页面的访问,同时也将对 /404.html 页面的访问也 deny 掉了。
所以正确的配置是加上下面几句:
location = /403.html { root /path/to/403/page/; allow all; internal; }
通过强制允许访问 /403.html 的方式来避免这个错误。下面加上 internal 的意思是这个页面不能被正常的访问到,只能因为 error_page 等内部原因而被访问到。详见这里