关于自签名证书,有两个工具,基于openssl和基于keytool,由于本次案例的开发语言是java,所以只介绍keytool,对openssl感兴趣的可以去查看官方文档以及技术大牛的博客。
Keytool 是一个Java 数据证书的管理工具 ,Keytool 将密钥(key)和证书(certificates)存在一个称为keystore的文件中。
在keystore里,包含两种数据:
keytool -genkey -alias server -keyalg RSA -keystore server.jks -validity 3650
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]: 127.0.0.1
您的组织单位名称是什么?
[Unknown]: cx
您的组织名称是什么?
[Unknown]: cx
您所在的城市或区域名称是什么?
[Unknown]: cx
您所在的省/市/自治区名称是什么?
[Unknown]: cx
该单位的双字母国家/地区代码是什么?
[Unknown]: CN
CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN是否正确?
[否]:y
输入 <webserver> 的密钥口令
(如果和密钥库口令相同, 按回车):
[解释]:生成的server.jks文件就是秘钥库,与.keystore格式的文件一样,都是秘钥库,不同格式而已
您的名字与姓名是什么?:这里一定要填写你服务器的域名,由于我是在本地测试就填写的本地IP
如果这里生成后,浏览器仍然有风险提示,使用扩展参数:
keytool -genkey -alias server -keypass [你的密码] -keyalg RSA -keysize 1024 -validity 365 -keystore server.jks -storepass [你的密码] -ext san=ip:127.0.0.1
C:>keytool -export -alias server -file server.cer -keystore server.jks
输入密钥库口令:
存储在文件 <server.cer> 中的证书
[解释]:此时从秘钥库server.jks中导出了server.cer证书文件,这个证书的作用就配置在浏览器或者是移动客户端(APP) ,以及这个证书就是自签名的证书,此时有的同学可能疑惑了,你可以使用命令行参数看下server.jks里面的内容是什么
keytool -list -v -keystore server.jks
输入秘钥库口令:
密钥库类型: JKS
密钥库提供方: SUN
您的密钥库包含 1 个条目
别名: server
创建日期: 2018-12-29
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN
发布者: CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN
序列号: 1f5419f8
有效期开始日期: Sat Dec 29 19:30:19 CST 2018, 截止日期: Tue Dec 26 19:30:19 CST 2028
证书指纹:
MD5: CE:3C:70:0A:3C:8F:**:**:**:**:**:**:**:BF:B4
SHA1: 92:6F:66:9E:A3:00:71:CC:45:07:C2:B8:05:73:DD:3B:A1:7C:E9:D3
SHA256: 28:1F:84:06:9D:F6:37:C7:FD:**:E2:**:C1:**:**:95:F5:B7:BF:F0:EB:20:DF:26:C2:7C:1F:C9:DA:10:47:AB
签名算法名称: SHA256withRSA
版本: 3
扩展:
#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
IPAddress: 127.0.0.1
]
#2: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 09 ** 03 42 ** 74 ** C8 DD B9 C3 2E 1A 8A D9 29 .m.B.tp........)
0010: 2E ** E4 D6 .,..
]
]
*******************************************
*******************************************
第二种方式-rfc输出
keytool -list -rfc -keystore server.jks
输入密钥库口令:
密钥库类型: JKS
密钥库提供方: SUN
您的密钥库包含 1 个条目
别名: server
创建日期: 2018-12-29
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIEH1QZ+DANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJD
TjELMAkGA1UECBMCY3gxCzAJBgNVBAcTAmN4MQswCQYDVQQKEwJjeDELMAkGA1UE
CxMCY3gxEjAQBgNVBAMTCTEyNy4wLjAuMTAeFw0xODEyMjkxMTMwMTlaFw0yODEy
MjYxMTMwMTlaMFUxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJjeDELMAkGA1UEBxMC
Y3gxCzAJBgNVBAoTAmN4MQswCQYDVQQLEwJjeDESMBAGA1UEAxMJMTI3LjAuMC4x
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoqjg9vVN6mOj+vpsJVR8
****************************************************************
****************************************************************
oLM9iRO1PluJ59fJpZtKi4ZOxGtVk8K6GUth+EHNtin1lsT81K1NexMg/GpK5ISp
Wy/HznFLs9xbIJR3YyZcW5uABo5hgKhFHATOF+thrVYn39ABgfdtNBcmzEAJgLdx
DeiXzgtOKm5a6vycwPvAD4D6BOXJsUzkCzBXJL2sxRXcEaDBAIcsIVHWHvuPvUMn
9QIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQJbQNC8XRwyN25
wy4aitkpLizk1jANBgkqhkiG9w0BAQsFAAOCAQEAbR8atpOtwUHpXsq57i3M5Or7
5fWDd32OWxEWkO/YPny2cEoG3GwUaJvZTieLCdtO1H1KHOg29akVgf2s6L3b4b8R
ljNt9T3eawuIa0qPh92vgKvcLFWroJ3ONLDPecJZpORnVyJ9OxzbtABlfkFqWQB+
****************************************************************
uRRn3q0iPBIQAaHEp0utxzlLh86k9Q0amNdZTHKWn7unLu5xwKh5tXaKgZc5/3yL
eMehq+iemjYRh1q7SqO9KqpnffTBSGMH5nN0nhdbFLO2aGydrfpc5zhT3lr4iQ==
-----END CERTIFICATE-----
*******************************************
*******************************************
这种输出方式直接可以查看公钥,至于私钥是什么,大家可以不必知道,只需要知道在server.jks里面就可以了,不影响你的项目进行
【注意】这里输出的公钥,是为了方便移动客户端(APP)的配置
至此,生成证书完毕,有的技术博客写的很复杂,生成了两对公私钥,让入门学者看的眼花缭乱,我在这里强调下,自签名的大可不必使用证书链,作为学习使用,本文中提出的步骤足够,不需要再生成额外的公私钥去生成客户端的证书,再导入的根证书的秘钥库中,这里可以直接使用根证书 ! ! !
把server.jks复制到项目中的根目录下面
由于博主的项目中使用的是springboot,内嵌了tomcat,所以比较简单,直接在pom文件中配置即可
server:
#服务端口
port: 8001
servlet:
# 项目contextPath
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数,默认为200
max-threads: 800
# Tomcat启动初始化的线程数,默认值25
min-spare-threads: 30
ssl:
key-store: server.jks
key-store-type: JKS
key-password: "password"
key-alias: server
【友情提示下】:一般实际工程中都是nginx中直接配置的,但是直接这样配置也没有关系,可以使用
为了让浏览器相信我们的证书签发机构,我们必须手动导入根证书,这里以Chrome浏览器为例,打开设置选项,选择高级功能
点击下一步把我们要导入的server.cer证书文件安装即可~
这样打开浏览器访问主页,就不会出现此网站不安全的提示了,如图
而不是像这样:
192.168.1.106是我的网络IP,由于我的证书上填写的是本地IP是127.0.0.1,所以这里使用192.168.1.106访问就是有危险,这个浏览器与服务器的认证机制大家可以去看下文档,关于ssl的过程就理解了。我在这里不再做叙述。
到此,浏览器的配置结束~
在移动端(APP)使用,大家经常要使用接口去访问一些服务器的资源,都是通过http协议去get、post,那么从http升级成了https怎么办?原来的方式肯定行不通,关于移动端服务器,大多数采用的https的都是使用自签名,那么如何让安卓系统相信我们使用的证书是安全的呢?
我们需要自己定义trustManager
Okhttp大家一定不陌生,具体介绍请访问官网,我在这里不做叙述。
网上给的资料Okhttp for https的答案各种各样,良莠不齐,大多数都是根据自己的项目来的,代码贴到自己的项目中根本不能起到作用,就算国外的Stack Overflow上回答的不是过时了,就是信任了所有的证书,直接不去验证证书的有效性,这样做配置https就没什么意义了。
我在这里给出一种方案,大家不必去了解原理怎么样,为了项目进行下去,直接使用即可,其实去了解原理,热认真看下代码就豁然开朗了,你会感叹,自己怎么写不出这么好的代码。但是能让项目进行下去,先直接用,火头再看原理,自己也是可以封装出来的。
我这里给出一个github上封装好的Okhttp for https的库,大家拿来用
Android Studio
compile 'com.zhy:okhttputils:2.6.2'
在添加代码,定义MyApplication 继承 Application,然后在manifests文件中注册MyApplication
这里只要是安卓开发入门者都懂什么意思,这里使用的myke就是我们第一步使用-rfc查看到的公钥
public class MyApplication extends Application
{
private String mykey = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWjCCAkKgAwIBAgIEH1QZ+DANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJD\n" +
"TjELMAkGA1UECBMCY3gxCzAJBgNVBAcTAmN4MQswCQYDVQQKEwJjeDELMAkGA1UE\n" +
"CxMCY3gxEjAQBgNVBAMTCTEyNy4wLjAuMTAeFw0xODEyMjkxMTMwMTlaFw0yODEy\n" +
"****************************************************************\n" +
"Y3gxCzAJBgNVBAoTAmN4MQswCQYDVQQLEwJjeDESMBAGA1UEAxMJMTI3LjAuMC4x\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoqjg9vVN6mOj+vpsJVR8\n" +
"agjZaRoCRaSv+erSI0uh3aav42oSBw7C0Nn75h+oj4FbjENa6N+ObNIqw0GQHwBA\n" +
"awc5EjRavJ8ys4mrlpbCaFhNDMUl3OX2Rg+cuZmi9E7y4IwE0abVL4FGyR3AGU2B\n" +
"****************************************************************\n" +
"Wy/HznFLs9xbIJR3YyZcW5uABo5hgKhFHATOF+thrVYn39ABgfdtNBcmzEAJgLdx\n" +
"DeiXzgtOKm5a6vycwPvAD4D6BOXJsUzkCzBXJL2sxRXcEaDBAIcsIVHWHvuPvUMn\n" +
"9QIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQJbQNC8XRwyN25\n" +
"****************************************************************\n" +
"5fWDd32OWxEWkO/YPny2cEoG3GwUaJvZTieLCdtO1H1KHOg29akVgf2s6L3b4b8R\n" +
"ljNt9T3eawuIa0qPh92vgKvcLFWroJ3ONLDPecJZpORnVyJ9OxzbtABlfkFqWQB+\n" +
"****************************************************************\n" +
"uRRn3q0iPBIQAaHEp0utxzlLh86k9Q0amNdZTHKWn7unLu5xwKh5tXaKgZc5/3yL\n" +
"eMehq+iemjYRh1q7SqO9KqpnffTBSGMH5nN0nhdbFLO2aGydrfpc5zhT3lr4iQ==\n" +
"-----END CERTIFICATE-----";
@Override
public void onCreate()
{
super.onCreate();
ClearableCookieJar cookieJar1 = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(getApplicationContext()));//设置缓存cookie,持久化cookie
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(new InputStream[]{new Buffer().writeUtf8(mykey).inputStream()}, null, null);
// CookieJarImpl cookieJar1 = new CookieJarImpl(new MemoryCookieStore());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000L, TimeUnit.MILLISECONDS)
.readTimeout(10000L, TimeUnit.MILLISECONDS)
.cookieJar(cookieJar1)
.hostnameVerifier(new HostnameVerifier()
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
})
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.build();
OkHttpUtils.initClient(okHttpClient);
}
}
【关于代码我就不解释了,大家都能看懂】
接下来直接在程序中使用OkHttpUtils就可以了
自定义MyStringCallback()
public class MyStringCallback extends StringCallback
{
@Override
public void onBefore(Request request, int id)
{
setTitle("loading...");
}
@Override
public void onAfter(int id)
{
setTitle("Sample-okHttp");
}
@Override
public void onError(Call call, Exception e, int id)
{
e.printStackTrace();
mTv.setText("onError:" + e.getMessage());
}
@Override
public void onResponse(String response, int id)
{
try {
mTv.setText(balance);
} catch (JSONException e) {
e.printStackTrace();
}
Log.e(TAG, "onResponse:complete");
}
@Override
public void inProgress(float progress, long total, int id)
{
}
}
这里我给出get https 的例子
String url = "https://192.168.*.*:8080/*";
OkHttpUtils
.get()//
.url(url)//
.addParams("key","value")
.build()//
.execute(new MyStringCallback());
至此,移动端配置完毕。
如果按照我的步骤一步步走,是不会出错的,如果有Bug,请各位仔细检查~
如果仔细看下这位大神封装的内容,很容易就理解了~
本文所写的文章足以应对项目需求了,后期优化就根据各位的业务逻辑需求了,如有问题欢迎讨论~
邮箱:[email protected]
如需转载,请通过邮箱联系本人或者注明出处,未经允许转载,必究 !!!