Git Product home page Git Product logo

blog's People

Contributors

leeweir avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

https优化

  1. 加密算法优化
    EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES,均采用前向安全性的强算法
    目前携程使用的是RSA证书,优先采用ECDHE密钥交换,RSA签名,对称算法优先使用AES
     优化依据:
    目前业界主流的密钥交换+签名有三种选择:
  1. RSA密钥交换(无需签名)
  2. ECDHE密钥交换、RSA签名
  3. ECDHE密钥交换、ECDSA签名
    由于256位ECC Key在安全性上等同于3072位RSA Key,加上ECC运算速度更快,在同等安全条件下,ECC算法所需的Key更短,ECC证书文件体积也比RSA证书小1/3左右,从效率看,ECDHE密钥交换+ECDSA签名无疑是最好的选择。但是,ECC证书的浏览器兼容性要差一些,在90%左右。 再加上ECDHE支持perfect forward secrecy ,能够实现false start,所以,综合安全和性能的最优cipher suite配置是: ECDHE-RSA-AES128-GCM-SHA256,它被配置在服务端cipher suite的第一个,在客户端浏览器支持的的情况下,以服务端配置的顺序优先。
     ToDo:
    在Nginx V1.11.0 (当前线上为v1.6.2)开始提供对RSA/ECC双证书的支持,根据在TSL握手协商得到的Cipher Suite ,如果支持ECDSA就返回ECC证书,否则返回RSA证书。在线上Tengine升级到最新Nginx后,我们可以使用ECC证书来提高体验,并保证兼容性。
  1. 证书链优化
    一条完整的证书链包含根证书—中间证书—站点证书,TLS的身份认证是通过证书链完成的,浏览器从站点证书开始递归校验父证书,直至出现信任的根证书。完整的证书链大小在4K左右,证书是在TLS握手期间传送,由于TCP初始拥塞窗口的存在,如果证书太长可能会增加TCP连接发送数据的次数,产生额外的往返开销,在弱网环境下延迟会增加得很明显。配置证书链的最佳实践是只包含站点证书和中间证书,服务端只需要发送两个证书,证书链大小控制在3Kb以内,以减少TLS握手时证书传输时间。

  2. False start
    TLS False Start指客户端在发送Change Cipher Spec Finished 同时发送应用数据,服务端在 TLS 握手完成时直接返回应用数据。这样,应用数据的发送实际上并未等到握手全部完成。在启用False Start之后,TLS阶段只需要 一次RTT就可以开始传输应用数据,相当于客户端提前发送应用层数据,无需等待服务端的确认。在服务端满足NPN和forward secrecy的条件下,大部分浏览器都会默认启用。

 优化后:
如下,在浏览器发送change cipher spec(315)之后,没有等待服务器的确认就立即发送了应用数据(316-319),相比没有启用的情况,可以优化50%的TLS握手时间

  1. Session Resumption
    Session Resumption是一种简化TLS握手的方法, 相比完全握手会少一个RTT的传输时间。Session Resumption的原理是将第一次TLS握手得到的对称密钥保存起来,在后续TLS握手时直接使用,以节省证书传送等开销。
    目前生产环境SLB已经启用了Session Identifier和Session Ticket这两种Session Resumption方式。
     Session Identifier
    Session Identifier是 TLS 握手中生成的 Session ID。服务端将 Session ID 协商后的信息存起来,浏览器也可以保存 Session ID,并在后续的 ClientHello 握手中带上它,如果服务端能找到与之匹配的信息,就可以完成一次简化握手。
    但是在集群环境下,相同client发起的请求会被round robin到各台SLB服务器,在不具备分布式session cache的场景下,单一用户的再次请求很难命中相同的SLB服务器,无法进行简化握手。
     Session Ticket
    Session Ticket 是用只有服务端知道的安全密钥加密过的会话信息,最终保存在浏览器端。浏览器如果在 下次ClientHello 时带上了 Session Ticket,只要服务器能成功解密就可以完成简化握手。
    但是,Session Ticket需要浏览器支持,目前浏览器端的支持率约50%,在移动端的支持率更低。

 Todo:
在完成Tengine 升级到Nginx的改造后,启动Nginx对分布式Session Cache的支持,在Session Identifier的基础上 实现Session Cache的多机共享机制,提高Session Identifier命中率,提高简化握手的比率。

  1. OCSP Stapling
    OCSP Stapling是指服务端在证书链中包含颁发机构对证书的 OCSP 查询结果,从而让客户端的浏览器跳过本地发起验证的过程。服务端通常有更快的网络,获取 OCSP 响应更容易,也可以将 OCSP 响应缓存起来。OCSP 响应本身经过了数字签名,无法伪造,所以 OCSP Stapling 技术既提高了握手效率,也不会影响安全性。由客户端发起的OCSP验证大约需要500ms,而由服务器端开启验证+响应缓存后,可以在TLS握手阶段,将OCSP响应和证书链一起下发给客户端浏览器,节省客户端在线验证的开销。
     Todo:
    6月在生产环境开启OCSP Stapling

  2. TLS Record Size
    服务器在建立TLS连接时,会为每个连接分配Buffer,这个Buffer叫TLS Record Size。Size值如果过大, 单个Record在TCP层会被分成多个包发送,必须等待这些包全部送到后才能解密,一旦出现丢包、拥塞、重传,握手延时将相应增加。而过小的TLS Record Size降低用户响应延时却降低了网络吞吐和利用率,所以需要合理设置TLS Record Size的大小。
    由于TLS Record Size要大于证书链和OCSP Stapling响应大小,证书链不会分成多个record;同时要小于初始拥塞窗口值,保证服务器在通信之初可以发送足够数据而不需要等待浏览器确认。
    Nginx默认的ssl_buffer_size为16k。根据携程实际的证书链大小,目前调整为6K。

https优化

优化方向:

  1. 减少 CPU 运算量
  • 使用 keepalive 长连接
  • 复用 SSL 会话参数
  1. 使用 HSTS 策略强制浏览器使用 HTTPS 连接
  • 添加 Strict-Transport-Security 头部信息
  • 使用 HSTS 预加载列表(HSTS Preload List)
  • 加强 HTTPS 安全性
  1. 使用迪菲-赫尔曼密钥交换(D-H,Diffie–Hellman key exchange)方案
  • 添加 X-Frame-Options 头部信息,减少点击劫持
  • 添加 X-Content-Type-Options 头部信息,禁止服务器自动解析资源类型
  • 添加 X-Xss-Protection 头部信息,防XSS攻击

协议和加密算法选择,采用cloudflare推荐

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;

复用ssl会话
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 180m;

添加hsts header
add_header Strict-Transport-Security max-age=15768000;

加强https安全性(可选项)
Google+:
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
Twitter:
strict-transport-security: max-age=631138519
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
PayPal:
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=14400
Facebook(配置了详细的CSP,关闭了XSS保护):
strict-transport-security: max-age=60
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 0
content-security-policy: default-src ;script-src https://.facebook.com http://.facebook.com https://.fbcdn.net http://.fbcdn.net .facebook.net .google-analytics.com .virtualearth.net .google.com 127.0.0.1: .spotilocal.com: chrome-extension://lifbcibllhkdhoafpjfnlhfpfgnpldfl 'unsafe-inline' 'unsafe-eval' https://.akamaihd.net http://.akamaihd.net;style-src * 'unsafe-inline';connect-src https://.facebook.com http://.facebook.com https://.fbcdn.net http://.fbcdn.net .facebook.net .spotilocal.com: https://.akamaihd.net ws://.facebook.com: http://.akamaihd.net https://fb.scanandcleanlocal.com:;

django singal post update

前不久一个新人问我如何在django的singal中实现post update,可是默认queryset的update是直接调用sql的,不会使用django orm中的save方法,signal中默认只有post save的方法。最后大致实现如下:

update() is converted directly to an SQL statement; it doesn't call save() on the model instances, and so the pre_save and post_save signals aren't emitted. If you want your signal receivers to be called, you should loop over the queryset, and for each model instance, make your changes and call save() yourself.

singals.py文件

-------------------自定义singal---------------
from django.dispatch import Signal
post_update = Signal(providing_args=["user"])

models.py文件

-----------對某个model,override其queryset中的update方法-----------
//引入自定义的signal文件
from tools import signals

class MyCustomQuerySet(models.query.QuerySet):
    def update(self, **kwargs):
        super(MyCustomQuerySet, self).update(**kwargs)
//update被调用时, 发送该singal
        signals.post_update.send(sender=self.model, user="xxx")
        print("finished!")

class MyCustomManager(models.Manager):
    def get_queryset(self):
        return MyCustomQuerySet(self.model, using=self._db)

class crontab_ping(models.Model):
    name = models.CharField(max_length=64, blank=True, null=True)
    objects = MyCustomManager()

callback.py文件:

-------接收signal,触发操作----------

from tools.signals import post_update

@receiver(post_update)
def post_update_callback(sender, **kwargs):
    print(kwargs['user'])
    print("post_update_success")

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.