升级Https的那些事
  分类: 其他   评论: 4 条

升级Https的那些事

in 其他 with 4 comment

一、为什么升级Https

1、苹果iOS强制开启ATS标准

苹果宣布2017年1月1日起,所有提交到App Store 的App必须强制开启ATS安全标准(App Transport Security),所有连接必须使用Https加密。(后延期了,具体日期还没确定,详情见:https://developer.apple.com/news/?id=12212016b)

2、Http协议无法加密数据

Http明文协议的缺陷,是导致数据泄露、数据篡改、流量劫持、钓鱼攻击等安全问题的重要原因。Http协议无法加密数据,所有通信数据都在网络中明文“裸奔”,通过网络的嗅探设备及一些技术手段,就可还原Http报文内容。

二、证书申请

1、货比三家

(1)、赛门铁克

优点:国际大厂,信誉保证
缺点:证书价格太贵,购买售后全为英文,不方便

(2)、沃通

优点:价格公道,国内多家网站使用,中文网站及客服
缺点:最便宜的证书不是沃通直接颁发

(3)、免费SSL

优点:免费,申请快
缺点:不适合企业使用

2、购买

综合考虑,个人可以考虑申请免费SSL,企业申请沃通的SSL

购买地址:http://www.wosign.com/price.htm

三、服务器配置证书(基于Wildfly(Jboss))

参考文档:http://www.cnblogs.com/maximo/p/5775627.html

1、配置证书

找到Wildfly的配置文件路径 wildfly9\standalone\configuration\standalone.xml,在应用域加入keystore信息,并将证书(juemuren.com.jks)复制到同目录下,如下:

<security-realm name="ApplicationRealm">
    <authentication>
        <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
        <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
    </authentication>
    <authorization>
        <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
</security-realm>
<!--以下为新增-->
<security-realm name="SslRealm">
    <server-identities>
        <ssl>
            <keystore path="juemuren.com.jks" relative-to="jboss.server.config.dir" keystore-password="123456"/>
        </ssl>
    </server-identities>
</security-realm>

2、配置https监听

打开wildfly9\standalone\configuration\standalone.xml,在应用域加入

<subsystem xmlns="urn:jboss:domain:undertow:3.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https"/>
        <!--以下为新增-->
        <https-listener name="https" security-realm="SslRealm" socket-binding="https"/>
        
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <filter-ref name="server-header"/>
            <filter-ref name="x-powered-by-header"/>
        </host>
    </server>
    <servlet-container name="default">
        <jsp-config development="true"/>
    </servlet-container>
    <handlers>
        <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
    </handlers>
    <filters>
        <response-header name="server-header" header-name="Server" header-value="WildFly/10"/>
        <response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
    </filters>
</subsystem>

3、设置http跳转https

(1)、全局自动监听

修改wildfly9/standalone/deployments/juemuren.com.war/WEB-INF\web.xml

<security-constraint>
    <web-resource-collection>
        <web-resource-name>juemuren.com</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

(2)、JS监听

在对应的页面html最开始添加下面的js代码:

<script type="type/javascript">
	var url=window.location.href;
	if (url.indexOf("https")<0) {
		url=url.replace("http", "https");
		window.location.replace(url);
	};
</script>

四、APP配置(安卓端)

参考文档:http://www.cnblogs.com/punkisnotdead/p/4788199.html

1、Volley启用https支持

(1)、修改Volley源码

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.http.AndroidHttpClient;
import android.os.Build;
import android.util.Log;

import com.android.volley.Network;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HttpClientStack;
import com.android.volley.toolbox.HttpStack;
import com.android.volley.toolbox.HurlStack;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

public class Volley {

    /**
     * Default on-disk cache directory.
     */
    private static final String DEFAULT_CACHE_DIR = "volley";
    private static BasicNetwork network;
    private static RequestQueue queue;
    private Context mContext;

    /**
     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
     *
     * @param context A {@link Context} to use for creating the cache dir.
     * @param stack   An {@link HttpStack} to use for the network, or null for default.
     * @return A started {@link RequestQueue} instance.
     */
    public static RequestQueue newRequestQueue(Context context, HttpStack stack, boolean selfSignedCertificate, int rawId) {
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        try {
            String packageName = context.getPackageName();
            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
            userAgent = packageName + "/" + info.versionCode;
        } catch (NameNotFoundException e) {
        }

        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                if (selfSignedCertificate) {
                    stack = new HurlStack(null, buildSSLSocketFactory(context, rawId));
                } else {
                    stack = new HurlStack();
                }
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                if (selfSignedCertificate)
                    stack = new HttpClientStack(getHttpClient(context, rawId));
                else {
                    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
                }
            }
        }

        Network network = new BasicNetwork(stack);

        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        queue.start();

        return queue;
    }

    /**
     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
     *
     * @param context A {@link Context} to use for creating the cache dir.
     * @return A started {@link RequestQueue} instance.
     */
    public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, null, false, 0);
    }

    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();

    }

    private static HttpClient getHttpClient(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();
        }
        if (keyStore != null) {
        }
        org.apache.http.conn.ssl.SSLSocketFactory sslSocketFactory = null;
        try {
            sslSocketFactory = new org.apache.http.conn.ssl.SSLSocketFactory(keyStore);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        }

        HttpParams params = new BasicHttpParams();

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);


        return new DefaultHttpClient(cm, params);
    }

    private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);

        Certificate cert = readCert(context, certRawResId);
        keyStore.setCertificateEntry("ca", cert);

        return keyStore;
    }

    private static Certificate readCert(Context context, int certResourceID) {
        InputStream inputStream = context.getResources().openRawResource(certResourceID);
        Certificate ca = null;

        CertificateFactory cf = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            ca = cf.generateCertificate(inputStream);

        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return ca;
    }
}

(2)、使用for other server的证书(juemuren.crt),将证书放在raw文件夹下,RequestQueue按下面获取

RequestQueue mQueue= Volley.newRequestQueue(context, null, true, R.raw.juemuren);

(3)、StringRequest延长超时时长

StringRequest request=new StringRequest();
request.setRetryPolicy(new DefaultRetryPolicy(30 * 1000, 2, 1.0f))

2、兼容旧版本

新版本的接口全换成https的,要想兼容旧版本,服务器配置http跳转https的监听可以设置为js版本的监听。

完成以上设置之后,就可以愉快的用Https访问网站了,enjoy~

欢迎关注我的公众号,及时获取最新文章推送。