httpd设置HTTPS双向认证

去年用tomcat、jboss配置过HTTPS双向认证,那时候主要用的是JDK自带的keytool工具。这次是用httpd + openssl,区别比较大

在网上搜索了很多文章,发现全面介绍的不多,或者就是版本比较旧了。所以把我配置的过程完整地记录下来,以供参考

首先要说明一下,HTTPS涉及到的内容非常繁杂,包括各种术语、命令、算法,我现在也没有完全搞清楚。本文会尽量把我知道的解释一下,但是深入的内容,暂时不打算深究了

一、环境

httpd: 2.4.4
openssl:1.0.1
os:ubuntu 12.04 LTS

二、场景

我准备在httpd上配置一个HTTPS双向认证,既向客户端表明自己的身份,也只允许特定的客户端访问。本文说的主要是作为server的角色的配置,至于作为client的配置,最后也会稍微介绍一下,但是不会详细说明

一般来说,互联网站不会去配置双向认证,因为客户端证书的分发和管理会比较麻烦,会把用户挡在门外,所以一般是不能这么做的。当然,像银行等对安全要求很高的网站,也会采用双向认证,比如U盾、安全控件什么的,其实就是固化的客户端证书

但是对于企业应用来说,客户一般是固定的,比如两个已知的系统对接、内部系统集成等。所以在企业应用领域,双向认证还是比较常见的

三、背景知识

证书(Certificate)是HTTPS的核心,但是其实证书并不是一个单一的东西,而是几种技术的综合

为了网络传输的安全,有很多种技术,最主要的是以下3种:

1、加密/解密

避免消息明文传输,对消息进行加密。早期一般是用对称加密算法,现在一般都是不对称加密,最常见的算法就是RSA。在后面的介绍中,也会多次看到RSA这个词

2、消息摘要

这个技术主要是为了避免消息被篡改。消息摘要是把一段信息,通过某种算法,得出一串字符串。这个字符串就是消息的摘要。如果消息被篡改(发生了变化),那么摘要也一定会发生变化(一般是这样的。如果2个不同的消息生成的摘要是一样的,那么这就叫发生了碰撞)

消息摘要的算法主要有MD5和SHA,在证书领域,一般都是用SHA(安全哈希算法)

3、数字签名

数字签名是为了验证双方的身份,避免身份伪造

以上三个技术结合起来,就是在HTTPS中广泛应用的证书(certificate),证书本身携带了加密/解密的信息,并且可以标识自己的身份,也自带消息摘要

四、在httpd中配置单向HTTPS

首先在%HTTPD_HOME%/conf/目录下,修改httpd.conf文件,加载必要的模块

Httpd代码  收藏代码
  1. LoadModule socache_shmcb_module modules/mod_socache_shmcb.so  
  2. LoadModule socache_dbm_module modules/mod_socache_dbm.so  
  3. LoadModule socache_memcache_module modules/mod_socache_memcache.so  
  4. LoadModule ssl_module modules/mod_ssl.so  


这里的前提是,在编译httpd的时候,已经编译了ssl模块。这个步骤看另一篇文档:
http://kyfxbl.iteye.com/blog/1902299

然后再导入默认的SSL配置文件,当然也可以选择不导入,在httpd.conf直接配置。但是导入默认的可以节省很多时间,并且默认的文件是用vhost配置的,不会跟main server冲突,可以算是一种最佳实践

Httpd代码  收藏代码
  1. # Secure (SSL/TLS) connections  
  2. Include conf/extra/httpd-ssl.conf  
  3.   
  4. <IfModule ssl_module>  
  5. SSLRandomSeed startup builtin  
  6. SSLRandomSeed connect builtin  
  7. </IfModule>  


然后打开%HTTPD_HOME%/conf/extra/目录,看一下httpd-ssl.conf,主要有以下几个配置

Httpd代码  收藏代码
  1. SSLEngine on  
  2. SSLCertificateFile "/usr/local/httpd/conf/server.cer"  
  3. SSLCertificateKeyFile "/usr/local/httpd/conf/server.key.pem"  
  4. #SSLCACertificateFile "/usr/local/httpd/conf/ca.cer"  
  5. #SSLVerifyClient require  
  6. #SSLVerifyDepth  10  


只要开启前3个,单向的HTTPS认证就配置好了。后面3个目前先注释掉,是后面双向认证才用到

然后重启一下httpd,会发现报错:

AH00526: Syntax error on line 106 of /usr/local/httpd/conf/extra/httpd-ssl.conf:
SSLCertificateFile: file '/usr/local/httpd/conf/server.cer' does not exist or is empty

这是因为httpd需要一个服务端的私钥(.key.pem),和一个服务端证书(.cer)。前面已经配置了这2个文件的路径,但是还没有创建。下一步就要创建这些文件

五、创建CA(Certificate Authority)

这个CA,也叫“根证书”

服务端做了一个证书,但是这是没有法律效力的,谁都可以自己做证书,就根本达不到安全的目的。所以就要有一个机构,负责来确认服务端的身份,然后统一的签发证书。这样才能有权威性

当浏览器通过HTTPS协议访问一个网站,网站首先会发过来一个自己的证书(certificate)。接下来浏览器就会到权威机构(CA),去 验证一下这个证书是不是它签发的。如果是的话,就信任这个网站的证书,继续访问;如果不是的话,要怎么处理就依赖于实现了。一般的浏览器会弹出一个警告, 让用户自己决定要不要继续访问。当然直接拒绝也是可以的

现在国际上有3大CA机构,如果是要自己做一个网站的话,如上所述,一般是需要请这些权威机构帮忙签发证书的。现在所有的主流浏览器,默认都安装 了这些CA的根证书,所以如果网站的证书是这些权威机构签发的,浏览器就不会发出警告了。比如支付宝,它的证书是由VeriSign签发的,所以访问支付 宝,浏览器不会发出警告



这里还有一个链条的关系,比如我有10个子网站,如果每个都要去找CA签发证书,就很麻烦。我可以找CA给我签发一个次级根证书,然后再用这个次 级根证书给自己签发10个证书。那么只要客户的浏览器里有CA根证书就可以了,这10个证书都可以通过认证,不要求客户安装次级根证书,原文见下:

引用
Intermediate CA certificates lie between the root CA certificate (which is installed in the browsers) and the server certificate (which you installed on the server).



如果是企业应用,那完全可以自己给自己当CA,因为可以要求目标用户(系统)安装自己的CA根证书,效果是一样的,还可以省下请权威CA签发证书的费用(互联网应用分发自己的CA到无数的互联网用户上,难度很大)

下面就介绍如何创建自己的CA

1、准备工作

先在随便一个目录,创建以下几个子目录:
/private
/certificates

其中private放的是私钥和CSR(后面会介绍),certificates里放的就是证书了

2、创建CA私钥

Openssl代码  收藏代码
  1. openssl genrsa -aes256 -out private/ca.key.pem 2048  


最后的参数是RSA密钥的长度,默认是512。2048其实长了一点,老的浏览器稍后会不支持,不过现在的主流浏览器都是支持的,所以问题不大

通过这个命令,私钥就创建好了,文件名是ca.key.pem

用这个命令,可以看一下刚才创建的这个私钥的信息

Openssl代码  收藏代码
  1. openssl rsa -noout -text -in private/ca.key.pem  


不过基本上,看也是白看,反正我是看不懂。只知道私钥里其实有2组数字,是用来形成公钥的,最后也会包含在证书里

引用

A private key contains a series of numbers. Two of these numbers form the "public key", the others are part of the "private key". The "public key" bits are included when you generate a CSR, and subsequently form part of the associated Certificate.



另外,最后的.pem扩展名,是表示该私钥用PEM编码。实际上私钥和证书都是用PEM编码的,PEM只是一种编码格式,不需要太在意。 httpd可以直接处理这种编码格式,但是浏览器和JAVA都不行,所以在需要的时候,会把编码从PEM改成PKCS,后面会介绍。只要知道证书和私钥都 有编码,只是编码是PEM还是PKCS的区别而已。就像"你好"可以用UTF-8编码,也可以用GBK编码一样,内容是不变的

3、创建CA签名请求

Openssl代码  收藏代码
  1. openssl req -new -key private/ca.key.pem -out private/ca.csr -subj "/C=CN/ST=SZ/L=SZ/O=kyfxbl/OU=kyfxbl/CN=*.kyfxbl.net"  


这里要注意的是,如果不用-subj参数,那么就会在命令行交互输入签发目标的身份识别信息,这叫DN(Distinguished Name)。其中别的都不要紧,最重要的是CN那一行,因为我这里是根证书,所以我设置为*.kyfxbl.net,这样我后面用这个CA签发的 www.kyfxbl.net、game.kyfxbl.net、news.kyfxbl.net……,全都是有效的

生成的签名请求文件,是ca.csr

Openssl代码  收藏代码
  1. openssl req -noout -text -in private/ca.csr  


同上,看不懂

4、自己签发CA根证书

Openssl代码  收藏代码
  1. openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey private/ca.key.pem -in private/ca.csr -out certificates/ca.cer  


这里参数很复杂,我也不太清楚准确的意思是什么,可以用openssl x509 -help自己研究一下

生成的ca.cer,就是最终的根证书了!这个文件非常重要,因为后续的服务端证书、客户端证书,都是用这个CA签发的,也要把它分发给客户,让他们导入到自己的浏览器或者系统中

查看的命令是:

Openssl代码  收藏代码
  1. openssl x509 -noout -text -in certificates/ca.cer  



5、把根证书从PEM编码转为PKCS编码

这步其实不是必选的,但是前面说过,JAVA环境是不能直接用PEM编码的证书的,很多浏览器也不行,所以有时候也需要转一下编码

Openssl代码  收藏代码
  1. openssl pkcs12 -export -cacerts -inkey private/ca.key.pem -in certificates/ca.cer -out certificates/ca.p12  


得到的ca.p12就是转码后的CA根证书,在不能直接用ca.cer的时候,就用ca.p12代替

六、签发服务端证书

现在CA根证书和私钥都有了,就可以开始签发服务端证书了(签发请求ca.csr是过程文件,有了cer就不再需要它了,要删掉也可以)。下面的命令和签发CA证书时都差不多,但是参数上有区别

1、创建服务端私钥

Openssl代码  收藏代码
  1. openssl genrsa -aes256 -out private/server.key.pem 2048  


2、创建服务端证书签发请求

Openssl代码  收藏代码
  1. openssl req -new -key private/server.key.pem -out private/server.csr -subj "/C=CN/ST=SZ/L=SZ/O=kyfxbl/OU=kyfxbl/CN=www.kyfxbl.net"  


和ca.csr的区别在于,这里的CN不是*.kyfxbl.net,而是www.kyfxbl.net,因为我现在是在为www.kyfxbl.net申请证书

3、利用CA根证书,签发服务端证书

Openssl代码  收藏代码
  1. openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA certificates/ca.cer -CAkey private/ca.key.pem -CAserial ca.srl -CAcreateserial -in private/server.csr -out certificates/server.cer  


这里和前面自己签发CA证书时,参数区别就比较大了,最后得到的server.cer,就是服务端证书

七、测试单向认证

把server.key.pem和server.cer拷贝到%HTTPD_HOME%/conf/目录下,然后重新启动httpd,会要求输入一个密码



然后访问http://localhost:443/,会报400错误:



接下来用https://localhost:443来访问,浏览器报警:



这里就是前面创建CSR时,输入的CN的作用,这个证书是为www.kyfxbl.net申请的,这里请求的地址却是localhost,不匹配所以报错。为了能用www.kyfxbl.net这个主机名来访问,就需要改一下/etc/hosts文件:

127.0.0.1       localhost
192.168.1.102   www.kyfxbl.net

然后就可以用www.kyfxbl.net来访问了,再试一下:https://www.kyfxbl.net/

这次浏览器还是告警,但是告警信息变了:



证书信息如下:



可以看到这个证书是由*.kyfxbl.net这个CA颁发的,浏览器不认识,所以不信任由这个CA签发的所有证书。接下来就需要把ca.cer 导入浏览器。这里直接导入server.cer也是可以的,但是后面如果又创建一个网站比如说www2.kyfxbl.net,那么又不行了。所以最好的 办法是直接导入CA根证书,那么后续只要是用这个根证书签发的证书,浏览器都会信任

导入前:



导入后:



再次访问,可以看到成功了,浏览器不告警,并且URL栏前面打了一个绿勾



八、配置双向认证

如果要配置服务器只允许合法的用户访问,就需要配置双向认证

配置为双向认证之后,除了服务端要发证书给客户端之外,客户端也要发客户端证书到服务端,服务端认证通过,才允许访问

Httpd代码  收藏代码
  1. SSLCACertificateFile "/usr/local/httpd/conf/ca.cer"  
  2. SSLVerifyClient require  
  3. SSLVerifyDepth  10  


在单项认证的基础上,再配置以上3个参数

SSLCACertificateFile,这个意思是当客户端发来客户端证书的时候,httpd用哪个CA根证书校验它

配置好了,还不能重启,因为现在客户端证书还没做好

这里要说明一下,客户端证书是怎么来的

有2种方式:

第一种,客户端也自己CA,然后签发证书给自己。把客户端的CA根证书发过来,配置成SSLCACertificateFile。这在互联网应用里基本是不可能的,安全和管理都是问题。但是在企业应用里,还是比较常见的,双方互相交换CA根证书

第二种,就用刚才服务端的CA根证书,签发一个客户端证书,发给用户,用户每次用这个证书来发请求,像银行,支付宝等等,用的是这种方式

当然理论上其实还有一种办法,就是客户自己去找权威CA签证书,但是这个是不可能的,因为很麻烦,找CA签也非常贵

本文用的是第2种方法。其实都是一样的。关键还是在CA根证书上,所以前面也说过了,CA根证书非常重要

九、签发客户端证书

1、创建客户端私钥

Openssl代码  收藏代码
  1. openssl genrsa -aes256 -out private/client.key.pem 2048  


2、创建客户端证书签发请求

Openssl代码  收藏代码
  1. openssl req -new -key private/client.key.pem -out private/client.csr -subj "/C=CN/ST=SZ/L=SZ/O=kyfxbl/OU=kyfxbl/CN=kyfxbl"  


这里的不同在于,这里的CN不是*.kyfxbl.net,也不是www.kyfxbl.net,随便填一个kyfxbl就好了,或者干脆叫user都没问题,反正是一个客户端证书

3、利用CA根证书,签发客户端证书

Openssl代码  收藏代码
  1. openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA certificates/ca.cer -CAkey private/ca.key.pem -CAserial ca.srl -CAcreateserial -in private/client.csr -out certificates/client.cer  


这里和签发server.cer基本是一样的

4、把客户端证书转换成p12格式

Openssl代码  收藏代码
  1. openssl pkcs12 -export -clcerts -inkey private/client.key.pem -in certificates/client.cer -out certificates/client.p12  


这步是必须的,因为稍后就需要把客户端证书导入到浏览器里,但是一般浏览器都不能直接使用PEM编码的证书

十、测试双向认证

把ca.cer拷贝到%HTTPD_HOME%/conf/目录下,重启httpd

然后再次访问https://www.kyfxbl.net/,结果这次不是警告,而是直接报错:



接下来要把client.p12导入到浏览器里

导入前:



导入的时候会要求输入密码,这是为了避免有人偷偷拷贝了别人的客户端证书,伪装成合法用户:



导入后:



然后再次访问,浏览器会要求选择证书。这个步骤是通过双向认证访问网站时必须的,但是平时访问银行、支付宝的时候貌似没有,这是因为这些网站为了简化用户的操作,都会要求用户安装什么“安全控件”,控件自动选择了证书



点击确定,访问成功!

十一、JKS等

到这里,用httpd配置双向HTTPS认证就完成了

本文说的是作为server的角色,要如何配置。但是在JAVA环境下,如果要以client的角色,通过双向认证发起请求,则还有些不同

这里实际上是要充当一个类似浏览器的角色,需要校验server certificate,还需要在发起请求的时候,把client certificate发过去

在JAVA里,是通过keystore和truststore来实现的,不在本文的讨论范围内。可以看一下其他的几篇博客,在HTTPS分类里

十二、参考资料

http://httpd.apache.org/docs/2.4/en/ssl/
http://linux.chinaunix.net/techdoc/net/2008/01/08/976172.shtml
《JAVA加密与解密的艺术》——作者梁栋

转载于:https://www.cnblogs.com/kabi/p/5623198.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序通讯录功能;uni-app微信小程序通讯录单选;uni-app微信小程序通讯录多选;uni-app微信小程序通讯录好友功能;uni-indexed-list使用;通讯录高度修改;

介绍&#xff1a;项目使用的是uni-app做的微信小程序&#xff1b;uni-app里原来就用一个组件uni-indexed-list&#xff0c;是用来做通讯录的&#xff1b;可以直接看官方案例也就是hello-uniapp-master下的导航栏&#xff1b;但是官方这个是多选&#xff0c;且没有默认选中功能&…

推荐! el-input 输入框类型;只能输入数字的输入框;保留两位小数输入框;只能输入正整数和0的输入框;手机号正则校验;车牌号码正则校验

去除多余的0看这篇 以下代码可直接复制使用&#xff1a; 以下代码可直接复制使用&#xff01; <template><div><a href"https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fraladdin#10">百度正则</a&…

Java多线程之JUC包:Semaphore源码学习笔记

若有不正之处请多多谅解&#xff0c;并欢迎批评指正。 请尊重作者劳动成果&#xff0c;转载请标明原文链接&#xff1a; http://www.cnblogs.com/go2sea/p/5625536.html Semaphore是JUC包提供的一个共享锁&#xff0c;一般称之为信号量。 Semaphore通过自定义的同步器维护了一个…

在vue项目中操作元素ref案例;

原博主链接 <!--* Description:会动的词云* Author: Vergil* Date: 2021-08-25 14:17:45* LastEditTime: 2021-08-25 17:08:15* LastEditors: Vergil --> <template><div class"wordCloud" ref"wordCloud"></div> </template&…

【C->Cpp】深度解析#由C迈向Cpp(2)

目录 &#xff08;一&#xff09;缺省参数 全缺省参数 半缺省参数 缺省参数只能在函数的声明中出现&#xff1a; 小结&#xff1a; &#xff08;二&#xff09;函数重载 函数重载的定义 三种重载 在上一篇中&#xff0c;我们从第一个Cpp程序为切入&#xff0c;讲解了Cpp的…

Session机制详解

虽然session机制在web应用程序中被采 用已经很长时间了&#xff0c;但是仍然有很多人不清楚session机制的本质&#xff0c;以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在 Java web application中应用session机制时常见的问题作出解答。 一、术语ses…

element-ui的表单校验;el-form表单校验;el-form表单自定义校验;手机号校验;车牌号校验;车牌号正则校验;手动校验表单某一项;手动清空表单的某一项校验结果

示例&#xff1a;代码在末尾 可以直接复制使用 一、基本属性认知&#xff1a; 1. required: true 会有 * &#xff0c; 但仅是触发最后点击提交按钮时&#xff0c;校验某一项位必填&#xff1b;与输入事件或者选择或者失焦时候 怎么校验无关 &#xff08;这时候的校验取决于是…

Eclipse For JavaSE安装、配置、测试

Eclipse For JavaSE安装、配置、测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.安装与配置 4.JavaSE开发测试 5.ADT安装与Android开发测试 6.注意事项 7.相关博文 >>看不清的图片可在新标签打开查看大图 1.概述 eclipse应该是Java开发界家喻户晓的IDE了&#xff0c;通…

epoll的两种模式

From: http://haoningabc.iteye.com/blog/1432958 linux异步IO浅析 http://hi.baidu.com/_kouu/blog/item/e225f67b337841f42f73b341.html epoll有两种模式,Edge Triggered(简称ET) 和 Level Triggered(简称LT).在采用这两种模式时要注意的是,如果采用ET模式,那么仅当状态发生…

关闭eslint检验;vue-cli3搭建的vue项目关闭eslint;脚手架3关闭eslint;

本文是解决关闭eslint的问题&#xff1b;如果想要开启eslint和配置&#xff0c;可以查看这篇开启eslint检验&#xff1b; 我们使用vue-cli3脚手架搭建vue项目时候&#xff0c;会默认选中eslint风格代码&#xff1b;如果想要关闭eslint检验&#xff0c;有如下两种方案&#xff…

转一篇关于并发和并行概念的好文,附带大神评论

转自&#xff1a;https://laike9m.com/blog/huan-zai-yi-huo-bing-fa-he-bing-xing,61/ 还在疑惑并发和并行&#xff1f; OK&#xff0c;如果你还在为并发&#xff08;concurrency&#xff09;和并行&#xff08;parallesim&#xff09;这两个词的区别而感到困扰&#xff0c;那…

MySQL索引背后的数据结构及算法原理-转

转 http://www.codinglabs.org/html/theory-of-mysql-index.html 摘要 本文以MySQL数据库为研究对象&#xff0c;讨论与数据库索引相关的一些话题。特别需要说明的是&#xff0c;MySQL支持诸多存储引擎&#xff0c;而各种存储引擎对索引的支持也各不相同&#xff0c;因此MySQL…

vue项目通过directives指令实现vue实现盒子的移动;vue拖拽盒子;vue移动;

vue项目&#xff1a;点击拖拽盒子&#xff1b;移动盒子&#xff1b; 代码可直接复制&#xff1a;&#xff08;注意需要在移动的盒子上添加 v-指令 注意采用固定定位&#xff09; <template><div class"far_box"><div>{{ msg }}</div><!-…

SuperAgent 中文乱码星号问号问题

看到星号问号了么&#xff0c;SuperAgent 爬取时中文乱码星号&#xff0c;只有中文是乱码&#xff0c;其它都是对的&#xff0c;肯定需要转义&#xff0c;找了两个小时&#xff0c;最后度娘看到个帖子 https://cloud.tencent.com/developer/article/1445392试了试&#xff0c;…

制作 Windows8   to Go

制作 Windows to Go 将准备好的 Windows 8 的镜像文件&#xff08;ISO 格式&#xff09;加载到虚拟光驱中去&#xff1b;将准备好的 USB 存储设备插入&#xff1b;打开控制面板&#xff0c;点击“Windows To Go”&#xff1b;在接下来的选项中按照步骤提示选择对应的 Win 8 的镜…

vue监听浏览器刷新和关闭;

注意&#xff1a;区分不了浏览器是触发了刷新还是关闭&#xff0c;而且提示的弹框是无法自定义的&#xff1b;如果有大佬有方法能区分&#xff0c;还请评论学习一下&#xff01;感谢&#xff01; 代码可直接复制&#xff1a; <template><div><div /></di…

计算文件的md5;vue计算文件md5值;计算图片的md5值;

github链接 1.先下载 npm i browser-md5-file -S2.在使用的vue页面引入和声明方法 import BMF from browser-md5-file const bmf new BMF()3.使用方法&#xff1a; function handle(e) {const file e.target.files[0];bmf.md5(file,(err, md5) > {console.log(err:, err);…

【转】【天道酬勤】 腾讯、百度、网易游戏、华为Offer及笔经面经

面试完毕&#xff0c;已跟网易游戏签约。遂敲一份笔经面经&#xff0c;记录下面试经过。类似于用日记记录自己&#xff0c;同时希望对师弟师妹有一定帮助。不是炫耀&#xff0c;只是希望攒RP&#xff0c;希望各位不要鄙视我。正所谓“饮水思源”。小弟来自广州华南理工大学&…

⭐️ vue项目使用微信表情;vue引入微信表情emoji;vue中使用微信表情包emoji;

以下的表情是通过引入emoji-vue插件做的&#xff1b;如果只是简单的显示个别表情&#xff0c;其实还可以用html的emoji的标签来完成 &#x1f61d;&#x1f64a;&#x1f47f;&#x1f525;&#x1f335;&#x1f344;&#x1f349;&#x1f1e8;&#x1f1f3;&#x1f61a;&am…

奈奎斯特采样定理:

&#xff08;1&#xff09;奈奎斯特采样定理&#xff1a; 当采样频率fs.max大于信号中最高频率fmax的2倍时&#xff0c;即&#xff1a;fs.max>2fmax,则采样之后的数字信号完整地保留了原始信号中的信息&#xff1b; 转载于:https://www.cnblogs.com/jocobHerbertPage/archiv…