由于之前项目一直使用的是http通信的,基本上能解决项目的一些个别问题,但是一旦出现了涉及到隐私问题,或者等同于金币性质的功能了,如果此时还采用http协议通信的话,那么就会很糟糕了。之前由于这个问题,导致出现被人刷金币,耍了RMB1000多,为了预防这种情况的存在,所以想到了https协议。
之前一直没接触过这方面的东西,以为只是简单的android https通信而已,却不料,跟服务器的配置有相关的重要性!
以下只是测试阶段的流程。
首先,测试服务器是nginx搭建的ip是:192.168.0.40 然后在nginx的配置文件里
server
{
listen 80;
listen 443;
ssl on;
ssl_certificate /home/wwwroot/ssl/hao-pem.crt;
ssl_certificate_key /home/wwwroot/ssl/hao.key;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
server_name www.haojiong.com haojiong.com;
index index.html index.htm index.php;
root /home/wwwroot/jiqun;
#rewrite ^(.*) https://192.168.0.40$1 permanent;
#error_page 404 456.txt;
location ~ .*\.(php|php5)?$
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fcgi.conf;
}
location /status {
stub_status on;
access_log off;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 12h;
}
access_log /home/wwwlogs/access.log access;
}
其中这两行代码是重要的
ssl_certificate /home/wwwroot/ssl/hao-pem.crt;
ssl_certificate_key /home/wwwroot/ssl/hao.key;
至于hao-pem.crt 跟hao.key这两个文件时怎么得来的,可以点此链接
点击打开链接 这里会流程性的介绍怎么得来的。
在此之前,请先用keytool生成一个keystore文件。
以上是服务器端的操作。接下来是客户端的操作流程
用之前生成keystore文件,然后转成bks文件,
这个连接有介绍怎么转转成bks。这个过程中会让你输入密码(我自己的理解就是一个密钥,这个密码是在客户端那边需要用到的)
之后android客户端代码如下
特别注意,这里我也不是搞的很懂
String URL = "https://192.168.0.40/new2.php";
这里的URL弄成ip形式的话,就可以正常运行。但是如果变成域名形式的话,就会出现乱七八糟的异常
这里我也不知道怎么回事
/**请求方法*/
public void DoRequest() {
// Instantiate the custom HttpClient
DefaultHttpClient client = MyHttpClient.setContext(this);
HttpGet get = new HttpGet(URL);
// 以 GET 方式读取服务器返回的数据
HttpResponse getResponse = null;
HttpEntity responseEntity = null;
try {
getResponse = client.execute(get);
responseEntity = getResponse.getEntity();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String string =null;
try {
string = inputStream2String(responseEntity.getContent());
Log.i(key, string);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**InputStream转成String方法*/
public static String inputStream2String(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = -1;
while ((i = is.read()) != -1) {
baos.write(i);
}
return baos.toString();
}
MyHttpClient类:
public class MyHttpClient extends DefaultHttpClient {
private static Context context;
public static MyHttpClient setContext(Context context) {
MyHttpClient.context = context;
return new MyHttpClient();
}
//
// public MyHttpClient(HttpParams params) {
// super(params);
// }
//
// public MyHttpClient(ClientConnectionManager httpConnectionManager,
// HttpParams params) {
// super(httpConnectionManager, params);
// }
//
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
// 用我们自己定义的 SSLSocketFactory 在 ConnectionManager 中注册一个 443 端口
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// 从资源文件中读取你自己创建的那个包含证书的 keystore 文件
InputStream in = MyHttpClient.context.getResources()
.openRawResource(Cer.keyRID); // 这个参数改成你的 bks文件名
try {
//上边说到的你自己输入的密码
String pass=Cer.passwd;
// 用 keystore 的密码跟证书初始化 trusted
trusted.load(in, pass.toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is
// responsible
// for the verification of the server certificate.
SSLSocketFactoryEx sf = new SSLSocketFactoryEx(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); // 这个参数可以根据需要调整,
return sf;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SSLSocketFactoryEx 类
public class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("SSL");
public SSLSocketFactoryEx(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
// TrustManager tm = new X509TrustManager() {
//
// public java.security.cert.X509Certificate[] getAcceptedIssuers() {
// return null;
// }
//
// @Override
// public void checkClientTrusted(
// java.security.cert.X509Certificate[] chain, String authType)
// throws java.security.cert.CertificateException {
//
// }
//
// @Override
// public void checkServerTrusted(
// java.security.cert.X509Certificate[] chain, String authType)
// throws java.security.cert.CertificateException {
//
// }
// };
TrustManager tm = new MyX509TrustManager();
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port,
autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
-------------------------到此结束----------------------------------
步骤:
1:先使用keytool生成keystore文件
2:将keystore变成crt文件
keytool -export -alias mykey -keystore keystore -file yidont.crt
3:将keystore变成*-pkcs8.key文件
java ExportPriv <keystore> <alias> <password> > exported-pkcs8.key
4:把2 3中生成的crt key文件放到服务器上,使用openssl
openssl x509 -out yidont-pem.crt -outform pem -text -in yidont.crt -inform der
openssl pkcs8 -inform PEM -nocrypt -in exported-pkcs8.key -out exported.key
5:将2中的crt转成客户端(手机)可识别的bks格式
注:记得先配这个 security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider jdk_home\jre\lib\security\ java.security
keytool -exportcert -alias test -file test.cert -keystore test.jks
keytool -importcert -keystore test.bks -file test.cert -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
这样的话,就算被人模拟请求了。也需要bks文件,其实bks文件我是理解成公钥,不知道对不对
就算被人反编译apk了,拿到了bks了(因为公钥本身就是要给其他人的),还需要一个密码,就是上边
所提到的一个密码。