HTTP通道安全学习笔记

HTTP通道安全学习笔记

  • 为什么HTTP通道不安全?

    客户端(浏览器)向服务端发起请求,到服务端响应回客户端的过程中,请求数据和响应数据都可能被窃听、被篡改。

  • 要做什么?

    避免通信过程数据被窃听、篡改、冒充。

这是一个通过窃听、篡改或冒充的手段,达到非法盈利的案例,请搜索关键词:90后 薅羊毛 话费

方案的演化

以下演化过程为个人整理相关后的理解,过程中碰到了博客说不清的,查了很久资料才总结出来,但是仅供参考

1 防止窃听

为了防止数据被窃听(被看到内容),可以对请求参数和响应结果进行加密。
在这里插入图片描述

由于客户端(浏览器)上运行的代码,是很容易可以看到源码的,所以如果使用对称加密,实际上用于加解密的密钥(yue,不是yao)是可以被人获得的,知道了密钥,就可以任意对数据进行加解密,从而伪造请求和响应结果,所以安全性很低。

那么我们可以使用非对称加密。非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

总结非对称加密就是:公钥加密私钥解密、私钥加密公钥解密
在这里插入图片描述

由于使用非对称加密,私钥只要保存在服务端并不被泄露出去,那么黑客就很难解密客户端请求参数,即使读到了响应结果,也没办法伪造响应结果,从而提高了系统安全性。

2 防止数据被篡改

防止篡改的基本方式是通过“签名”来实现。即所有参数通过一种摘要算法(比如哈希)计算出一个摘要值,再用加密算法对摘要进行加密得到签名,只要黑客不知道加密的密钥,就不能伪造出这个签名,从而达到了防篡改的目的。

例如:

  • 假设某一次HTTP请求过程中,请求参数集U有{a,b,c} 3个参数
  • 客户端有一个黑客不知道的密钥 X
  • 客户端通过摘要算法(比如对 a=1&b=2&c=3 计算hash code,得到 Y)
  • 用黑客不知道的密钥 X 加密 Y 得到一个签名,这个签名代表着这次请求的业务参数,签名会一起作为请求参数传给服务端,供服务端验证
  • 由于黑客不知道密钥,无法伪造签名,所以最多只能改a、b、c这3个参数,但是服务端通过相同算法,对a、b、c计算签名,得出的结果与原签名不匹配,就说明本次请求被第三方伪造了,请求就可以判定为无效。

在这里插入图片描述

3 验证服务端下发的公钥

由于请求是可以被劫持的,所以如果第三方劫持了客户端到服务端的通道,那么黑客就可以伪造公钥,从而劫持客户端所有请求。要解决这个问题,我们就要能够验证服务端的身份(形象的比喻就是把你的身份证给我看看)。

在HTTP通信中,我们使用证书机制来验证服务端的身份。

证书就可以看做是服务器的身份证,那么身份证的颁发机构就是CA机构(看作是公安局),CA机构的证书是收费的,当然也可以做一个自签的证书,比作商户的会员卡性质,只要客户端认你的会员卡就行。

有了证书后,我们的请求流程就成了这样:
在这里插入图片描述

CA证书机制是如何保证服务端身份确认的准确性?

  • 首先生成证书之前,会先生成一对证书专用的公私钥对,公钥pub_key会放到证书里,私钥pri_key配在服务端,不对外公布
  • 证书中保存了服务端的域名、证书颁发机构、证书有效期、公钥、签名(签名是通过 [第2点 防止数据被篡改](#2 防止数据被篡改)中描述的方法生成的。当然这些证书内的信息、签名应该会经过私钥pri_key加密,这里不作详细研究)等信息
  • 客户端拿到证书后,会用公钥解密出证书内容,匹配当前要访问在站点域名是否一致、签名是否有效、正式是否过期等,这样就确认好了证书
  • 此时还有一个问题存在,虽然证书是真的,但是我怎么知道证书就是你的(身份证上的人是你)?
    • 有这样的问题是因为证书是公开的,任何人访问站点都可以获得这个证书,所以自然也会被恶意利用
    • 第三方劫持通道后,可以那着真的证书来伪造你的请求内容,所以接下来就是如何确认证书和服务端的关系
  • 客户端验证证书没问题后,会生成一个随机的码 A,A 通过摘要算法(如哈希)计算并用公钥pub_key加密后得到 B,客户端将A 和 B 同时发给服务端,服务端用私钥pri_key解密对比,再用私钥pri_key用类似的算法加密 A ,得到加密结果 C,将 C 响应回客户端,由客户端再作一遍验证这样就可以确认服务端的身份了(基于私钥没有泄露)
4 加解密方案的优化

达成一个共识:使用对称加密的效率要远高于非对称加密。

此时,我们验证了服务端的身份了,那么本次连接就已经是安全的了,我们此时的目的就是单纯的不让人看到明文内容就好了(我们已经面对面了,解决了被篡改和冒充的风险,现在只需要不让其他人听懂我们之间的谈话就行了),所以如果还用非对称加密(基于公私钥)那么效率就会比较低,我们可以选择用对称加密来提高局部的效率。

5 SSL的基本原理

SSL就是基于上述我自己推导的过程产生的,当前其中还有很多内容并没有提及,但是我认为初步掌握SSL所需的要点,在上文中都已经提及了,下面简单总结一下SSL的原理。
在这里插入图片描述

  • 在确认随机码的时候数据用公钥加密,所以没有私钥是无法解密去伪造响应内容的;
  • 所以随机码只有客户端和服务端之间才知道,以这样的机制,就可以防止第三方窃听、伪造、冒充了。

SpringBoot内置HTTPS配置

本方法适用于小型的SpringBoot单体项目,可以直接将SSL证书配置到SpringBoot内置的Tomcat上,从而开启SSL通信。但是不适用于带有负载均衡器或微服务集群乃至分布式的大型应用场景。

使用keystore工具,它是jdk自带的一项工具,在jdk/bin下,keytool.exe

命令:

 -certreq            生成证书请求
 -changealias        更改条目的别名
 -delete             删除条目
 -exportcert         导出证书
 -genkeypair         生成密钥对
 -genseckey          生成密钥
 -gencert            根据证书请求生成证书
 -importcert         导入证书或证书链
 -importpass         导入口令
 -importkeystore     从其他密钥库导入一个或所有条目
 -keypasswd          更改条目的密钥口令
 -list               列出密钥库中的条目
 -printcert          打印证书内容
 -printcertreq       打印证书请求的内容
 -printcrl           打印 CRL 文件的内容
 -storepasswd        更改密钥库的存储口令

使用 "keytool -command_name -help" 获取 command_name 的用法
1 生成密钥对
-genkeypair命令选项:

 -alias <alias>                  要处理的条目的别名
 -keyalg <keyalg>                密钥算法名称
 -keysize <keysize>              密钥位大小
 -sigalg <sigalg>                签名算法名称
 -destalias <destalias>          目标别名
 -dname <dname>                  唯一判别名
 -startdate <startdate>          证书有效期开始日期/时间
 -ext <value>                    X.509 扩展
 -validity <valDays>             有效天数
 -keypass <arg>                  密钥口令
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

执行生成命令

keytool.exe -genkeypair -alias aliias -keypass 123456 -keyalg RSA -storetype PKCS12 -validity 365 -keystore D:\alias.keystore -storepass 123456 -ext san=dns:localhost

查看密钥对内容

keytool.exe -list -v -keystore D:\alias.keystore
keytool.exe -list -rfc -keystore D:\alias.keystore
2 导出证书
-exportcert选项:

 -rfc                            以 RFC 样式输出
 -alias <alias>                  要处理的条目的别名
 -file <filename>                输出文件名
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

执行导出证书命令

keytool.exe -exportcert -alias alias -keystore D:\alias.keystore -file D:\alias.cer

导出的这个证书在客户端(PC)上安装到“受信任的根证书颁发机构”下,关闭浏览器重新打开访问系统即可。

3 配置SpringBoot

以下为application.yml的相关配置

# 服务相关配置
server:
  # 服务启动端口号
  port: 443
  ssl:
    key-alias: alias
    key-store: classpath:aliias.keystore
    key-store-type: JKS
    key-store-password: 123456
    key-password: 123456

aliias.keystore拷贝到src/main/resources下,与application.yml同级目录中(或指定位置,需要修改server.ssl.key-store配置值)。

clean maven依赖后,可以运行测试,此时可以访问https://localhost,但https这部分还是处于红色警告标识(无法验证该证书的有效性),需要把alias.cer文件安装在客户端(PC)本地的“受信任的根证书颁发机构”下。安装后清除缓存重启浏览器,重新范围系统即可。

需要了解的是,cer证书我们需要通过前端触发,让用户进行下载安装,以此来信任站点,IE有ActiveX可以做,其他浏览器的话,目前还是通过js+用户手动安装实现(不然就花钱买CA机构的证书吧,一劳永逸)。

如果要允许用户使用http访问,那么我们需要配置http转https,这里不作详细记录。

基于Nginx的HTTPS配置

1 安装Openssl

通过该网站,下载可在Windows下运行安装的安装包 http://slproweb.com/products/Win32OpenSSL.html

安装后即可开始创建证书

注意,安装过程中,可以选择将可执行文件存放在安装目录内的bin目录下,这样方便找

打开命令窗口,进入安装目录下的bin目录中

2 创建证书
  • 生成服务端私钥文件

    openssl genrsa -des3 -out D:\server.key 1024
    
  • 建立证书的申请文件root.csr

    openssl req -new -key D:\server.key -out D:\server.csr
    

    输入国家,省份,城市,公司信息,证书发送邮箱地址和证书密码(服务器端)

  • 免密,放在Nginx中后,每次使用不用输密码

    复制server.key,生成新的文件server.key.src,然后执行下面命令

    openssl rsa -in D:\server.key.src -out D:\server.key
    
  • 生成一个有效期1年的证书

    openssl x509 -req -days 365 -signkey D:\server.key -in D:\server.csr -out D:\server.crt
    
3 配置Nginx

Nginx 的配置文件nginx.conf中,默认是带有ssl配置模板的,我们只要稍微改改就可以用了,具体Nginx需要如何配置,这里不作详细说明。

    upstream app {
        server    127.0.0.1:8094;
    }
    
    # HTTPS server
    #
    server {
        listen       443 ssl;
        server_name  localhost;

        ssl_certificate      D://server.crt;
        ssl_certificate_key  D://server.key;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            proxy_pass http://app;
        #    root   html;
        #    index  index.html index.htm;
        }
    }

接口防篡改

主要用于开放API的时候(服务端对服务端,或者客户端对服务端),通常会对请求参数进行加密和签名。

签名过程通常可以有这样几个步骤:

  1. 请求参数打乱顺序;
  2. 请求参数组装成一个串,然后通过摘要算法加密,其中会用一个只有双方约定好的密钥加密,来保证双方都可以相互加解密,其次还会有一个调用方的身份标识,典型的例子就是appId和secret;
  3. 这样就保证了数据不容易被篡改,同时为了不被窃听,还可以把所有请求参数都加密。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值