由于需求和安全的考虑,需要将上一篇文档,使用NanoHttpd搭建的http server改成https的协议,但由于我们测试没办法正式的CA机构颁发的数字证书,所以就使用自签名的方式来验证https server。
由于查看源码得知,NanoHttpd是支持Https的,Support for HTTPS (SSL)
二、Https协议相关的基础知识HTTPS的基本工作原理想必对于许多开发者来说是非常熟悉的了,我们一起先回忆一下HTTP常见的八股文中的描述:
1.客户端(浏览器)访问 HTTPS 的URL;
2.服务器返回 HTTPS 使用的 CA 证书;
3.客户端(浏览器)验证 CA 证书是否为合法证书;
4.验证通过,证书合法,生成一串随机数并使用公钥(证书中提供的)进行加密;
5.发送公钥加密后的随机数给服务器;
6.服务器拿到密文,通过私钥进行解密,获取到随机数(公钥加密,私钥解密,反之也可以);
7.服务器把要发送给浏览器的内容,使用随机数进行加密后传输给客户端(浏览器);
8.此时客户端(浏览器)可以使用随机数进行解密,获取到服务器的真实传输内容。
那么我们回到我们的主题里,首先需要知道CA证书是什么,CA是证书颁发机构(Certificate Authority)的缩写,那么CA证书就是证书机构颁发的一种数字证书,为什么需要这个机构来颁发证书呢?可以理解为就是一个第三方担保机构,这个担保机构保证了在客户端和服务器的通讯阶段的安全,这样客户端只要是看到证书是这个担保机构担保过的,那就会认可这个服务器并和它进行后续交互,反之其他证书都是不合法的,不会进行更进一步的交互了。
其次,这个证书不光是用来证明其合法性,其中还包含了一个公钥,公钥是什么呢?这边就涉及到一些密码学相关知识点了,我们需要先知道非对称加密的一点概念,可以猜出来,有非对称加密那肯定有对称加密,对称加密就是使用同一把密钥进行加密和解密,而非对称加密会用到2个密钥,一把公钥和一把私钥进行加密和解密,公钥会公开出去给客户端,而私钥会保存在本地防止泄漏,所以会更安全,使用这个公钥加密后的数据可以被私钥解开,反过来也是一样的,在上面的HTTPS的连接过程中,1-6步骤所涉及到的就是非对称加解密过程,而后续则会采用对称加密的方式,即使用一个随机数充当了对称加密的密钥进行了通讯,这样一方面是为了提高通讯的效率更重要的是为了保证安全,因为如果还使用原有的公钥和私钥的方式在服务端使用私钥加密,那么只要有公钥的客户端都可以截获服务端发来的信息进行解密,显然这样是不行的。
知道了概念后,那自签证书的概念就是我们自己充当这个CA机构给自己颁发一个证书,然后想办法让客户端信任这个证书(一般的默认做法是系统会有一个受信任的证书列表,其中就会有存放一些CA机构的根证书),并且证书里面包含了我们的公钥,客户端使用这个公钥进行数据加密,再传输数据,服务端接收并用私钥解开,从而完成整个加解密的通讯过程。那接下来我们就来模拟这样一个通讯过程
三、自签名证书过程使用KeyStore Explorer创建一个BKS-V1密钥库,并将其作为“keystore.bks”保存到android的raw文件夹。或者,您也可以使用以下代码来创建密钥库文件,然后只需使用密钥库资源管理器将其打开,并将其类型更改为 BKS-V1。
密钥库资源管理器 - 下载 (keystore-explorer.org)
windows打开cmd终端,粘贴下面这一段命令,其中的-storepass后面的值可以自己修改成自己的storepass。
keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.bks -storepass myKeyStorePass -validity 360 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1 -validity 9999
上面的命令应该不难理解,就是你给密钥文件设置的生成位置,key alias
、key password
和key store、
validity ,回车后,需要继续按照提示输入相关信息,依次填写好信息后,输入 Y
确认信息即可。上面一行的storepass为myKeyStorePass,别名为selfsigned,有效期为360天,keystore.bks保存在了C盘的当前用户目录(C:\Users\sunbinkang)。
然后用上面安装好的密钥库资源管理器KeyStore Explorer去找到这个keystore.bks文件打开,打开的时候输入上面的storepass密码就行(ps:我被这里坑了好久,记住要输入storepass的这个密码,不是keypass的密码),打开后,找到Tools--->change KeyStore Type--->BKS-V1保存就行。
四、Android项目中使用自签名证书将上一步中生成的keystore.bks做了type转换后,将文件放入到项目的main->res->raw目录下,如果没这个文件夹,新建一个就行;
在HttpServer.kt的文件中的次构造中加入如下代码:
//服务器信任的客户端证书
constructor(context: Context, hostname: String?, port: Int) : this(hostname, port) {
//从文件中拿到流对象
val keystoreStream: InputStream =
context.resources.openRawResource(R.raw.keystore)
//拿到keystore对象
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
//keystore加载流对象,并把storepass参数传入
keyStore.load(keystoreStream, "myKeyStorePass".toCharArray())
val keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
//这里的第二个参数就是密钥密码,keypass
keyManagerFactory.init(keyStore, "*******".toCharArray())
//调用 NanoHttpd的makeSecure()方法
makeSecure(makeSSLSocketFactory(keyStore, keyManagerFactory), null)
}
五、postman或者浏览器发起https请求验证
第一张图是因为自签名的原因,需要用户自己手动信任证书。图二为发起的https的get 请求,请求成功。
至此,我们在Nanohttpd的httpserver的基础上做了支持https协议。
最后附上mainactivity的代码。
class MainActivity : AppCompatActivity() {
var mHttpServer: HttpServer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mHttpServer = HttpServer(MainActivity@ this, HTTP_IP, HTTP_PORT)
//三种启动方式都行
// mHttpServer.start()
// mHttpServer.start(NanoHTTPD.SOCKET_READ_TIMEOUT)
mHttpServer?.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false)
}
override fun onDestroy() {
super.onDestroy()
mHttpServer?.stop()//停止
}
}
项目代码地址:GitHub - sunbinkang/NanoHttpdDemo: android app 使用nanohttpd搭建http server,并且支持https协议
需要注意的是,项目中的raw文件需要你自己生成证书,因为证书是有密码的,我自己证书的密码在代码中用******标记了,所以拿到我的keystore.bks也没用。所以要想跑起来就得自己生成了。具体生成看步骤,有不懂的提问找我。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)