分类 生活随笔 下的文章

HTTPS连接过程以及中间人攻击劫持

一 、HTTPS连接过程及中间人攻击原理

https协议就是http+ssl协议,如下图所示为其连接过程:

1.https请求

客户端向服务端发送https请求;

2.生成公钥和私钥

服务端收到请求之后,生成公钥和私钥。公钥相当于是锁,私钥相当于是钥匙,只有私钥才能够打开公钥锁住的内容;

3.返回公钥

服务端将公钥(证书)返回给客户端,公钥里面包含有很多信息,比如证书的颁发机构、过期时间等等;

4.客户端验证公钥

客户端收到公钥之后,首先会验证其是否有效,如颁发机构或者过期时间等,如果发现有问题就会抛出异常,提示证书存在问题。如果没有问题,那么就生成一个随机值,作为客户端的密钥,然后用服务端的公钥加密;

5.发送客户端密钥

客户端用服务端的公钥加密密钥,然后发送给服务端。

6.服务端收取密钥,对称加密内容

服务端收到经过加密的密钥,然后用私钥将其解密,得到客户端的密钥,然后服务端把要传输的内容和客户端的密钥进行对称加密,这样除非知道密钥,否则无法知道传输的内容。

7.加密传输

服务端将经过加密的内容传输给客户端。

8.获取加密内容,解密

客户端获取加密内容后,用之前生成的密钥对其进行解密,获取到内容。

中间人劫持攻击

https也不是绝对安全的,如下图所示为中间人劫持攻击,中间人可以获取到客户端与服务器之间所有的通信内容。

中间人截取客户端发送给服务器的请求,然后伪装成客户端与服务器进行通信;将服务器返回给客户端的内容发送给客户端,伪装成服务器与客户端进行通信。
通过这样的手段,便可以获取客户端和服务器之间通信的所有内容。
使用中间人攻击手段,必须要让客户端信任中间人的证书,如果客户端不信任,则这种攻击手段也无法发挥作用。

二、中间人攻击的预防

造成中间人劫持的原因是 没有对服务端证书及域名做校验或者校验不完整,为了方便,直接采用开源框架默认的校验方式进行https请求

如volley

OKhttp3.0

a15b4afegw1f8kuli8awuj20la0k40wd.png

预防方法:

预防方式有两种

  1. 针对安全性要求比较高的 app,可采取客户端预埋证书的方式锁死证书,只有当客户端证书和服务端的证书完全一致的情况下才允许通信,如一些银行类的app,但这种方式面临一个问题,证书过期的问题,因证书有一定的有效期,当预埋证书过期了,只有通过强制更新或者要求用户下载证书来解决。

以volley为例:校验的实现方式如下

通过预埋证书创建 SSLSocketFactory;

private static SSLSocketFactory buildSSLSocketFactory(Context context, int certRawResId) {
    KeyStore keyStore = null;
    try {
        keyStore = buildKeyStore(context, certRawResId);
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = null;
    try {
        tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }

    SSLContext sslContext = null;
    try {
        sslContext = SSLContext.getInstance("TLS");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    try {
        sslContext.init(null, tmf.getTrustManagers(), null);
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }

    return sslContext.getSocketFactory();

生成 经过ssl校验及 域名校验的connection

  1. 针对安全性要求一般的app,可采用通过校验域名,证书有效性、证书关键信息及证书链的方式

以volley为例,重写HTTPSTrustManager 中的checkServerTrusted 方法,同时开启域名强校验

三、Webview的HTTPS安全

目前很多应用都用webview加载H5页面,如果服务端采用的是可信CA颁发的证书,在 webView.setWebViewClient(webviewClient) 时重载 WebViewClient的onReceivedSslError() ,如果出现证书错误,直接调用handler.proceed()会忽略错误继续加载证书有问题的页面,如果调用handler.cancel()可以终止加载证书有问题的页面,证书出现问题了,可以提示用户风险,让用户选择加载与否,如果是需要安全级别比较高,可以直接终止页面加载,提示用户网络环境有风险:

不建议直接用handler.proceed()。如果webview加载https需要强校验服务端证书,可以在 onPageStarted() 中用 HttpsURLConnection 强校验证书的方式来校验服务端证书,如果校验不通过停止加载网页。当然这样会拖慢网页的加载速度,需要进一步优化,具体优化的办法不在本次讨论范围,这里也不详细讲解了。

MongoDB + ElasticSearch + Nginx 简单试用

install jdk:

wget http://download.oracle.com/otn-pub/java/jdk/8u77-b03/jdk-8u77-linux-x64.rpm #以实际地址为准
sudo rpm -ivh jdk-8u77-linux-x64.rpm
java -version

install elasticsearch:

wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/rpm/elasticsearch/2.3.1/elasticsearch-2.3.1.rpm
sudo rpm -ivh elasticsearch-2.3.1.rpm
sudo chkconfig --add elasticsearch

config elasticsearch:

mkdir -p /home/worker/data/elasticsearch/data
mkdir -p /home/worker/data/elasticsearch/log
mkdir -p /home/worker/data/elasticsearch/pid
sudo chown -R worker:worker /etc/elasticsearch
export ES_HEAP_SIZE=15000000    # half useable memory

sudo vi /etc/sysconfig/elasticsearch

DATA_DIR=/home/worker/data/elasticsearch/data
LOG_DIR=/home/worker/data/elasticsearch/log
PID_DIR=/home/worker/data/elasticsearch/pid
ES_HEAP_SIZE=15g
ES_USER=worker
ES_GROUP=worker

sudo /usr/share/elasticsearch/bin/plugin install lmenezes/elasticsearch-kopf

配置:
sudo vi /etc/elasticsearch/elasticsearch.yml

cluster.name: elasticsearch
node.name: node-${HOSTNAME}
network.host: 10.100.30.105
discovery .zen.ping.unicast.hosts: ["10.100.30.105","10.100.30.106"]

sudo service elasticsearch start

curl 10.100.30.105:9200

mongo-connector elastic2-doc-manager:

sudo pip install elastic2-doc-manager

hosts: 127.0.0.1 search.test.com

nginx负载均衡配置:

upstream elasticsearch {
    server 10.100.30.105:9200;
    server 10.100.30.106:9200;
    keepalive 100;
}
server {
    server_name search.test.com;
    listen 80;
    location / {
        proxy_pass http://elasticsearch;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header  X-Real-IP  $remote_addr;
        access_log off;
        allow all;
    }
}

openresty:

wget https://openresty.org/download/openresty-1.9.7.4.tar.gz
./configure --prefix=/home/worker/openresty --with-pcre-jit --with-http_stub_status_module --with-http_ssl_module
sudo /home/worker/nginx/sbin/nginx -s reload

curl search.test.com

ab -n 1000000 -c100 -k http://10.100.30.105:9200/
ab -n 1000000 -c100 -k http://search.test.com/

http://search.test.com/_plugin/kopf/#!/cluster

import MongoDB data:

mongoimport -h 127.0.0.1:27017 -d user_center -c users users.data.201601061

db.users.count()

2640260 264万 0.625GB

config = {
    _id: "RS0",
    members: [
        {_id: 0, host: "10.100.30.52:27017"},
        {_id: 1, host: "10.100.30.52:27018"},
    ]
}

mongo-connector:

config.json
{
    "mainAddress": "10.100.30.52:27017",
    "oplogFile": "/home/worker/data/mongo-connector/oplog.timestamp",
    "noDump": false,
    "batchSize": -1,
    "verbosity": 0,
    "continueOnError": true,
    "logging": {
        "type": "file",
        "filename": "/home/worker/data/mongo-connector/mongo-connector.log"
    },
    "namespaces": {
        "include": ["user_center.users"]
    },
    "fields": ["email", "loginType", "certificated", "destroyed", "regDate", "mobile", "detail"],
    "docManagers": [
        {
            "docManager": "elastic2_doc_manager",
            "targetURL": "10.100.30.106:9200",
            "args": {
                "clientOptions": {"timeout": 200}
            },
            "autoCommitInterval": 0
        }
    ]
}

nohup mongo-connector -c config.json > /home/worker/data/mongo-connector/hup.log 2>&1 &

ab:

query.json
{
    "query": {
        "match": {
            "detail.lowerName": "张三"
        }
    }
}

query1.json
{
    "query": {
        "match": {
            "email": "163.com"
        }
    }
}

ab -n 10000 -c100 -k -p query.json "http://search.test.com/user_center/users/_search"

ab -n 10000 -c100 -k "http://search.test.com/user_center/users/_search?size=1&q=detail.lowerName:张三"

ab -n 10000 -c100 -k "http://search.test.com/user_center/users/_search?size=1&q=email:gmail"

2016年春节总结

嗯:

本年度最大的收获就是爱情,今天就是情人节,嗯?

年中离开北京来到广州,认识了很多优秀的朋友,收获颇多

今年继续加油,希望爱情事业双丰收!

要回成都了!也很期待!