openssl是一个条件实现了上百种算法、实现了单向加密工具等一组套件,代码量很小但是功能强大。它有三部分组成:
openssl enc加密解密命令:
参数 | 说明 |
-des3 | 是指定加密算法 |
-a | 是输出文件按base64内容输出,否则就是二进制的 |
-in |
要加密的文件 |
-out |
加密后的文件 |
-salt |
加盐 |
-d | 表示解密 |
openssl enc -des3 -a -salt -in /work/aaa.txt -out /work/aaa.enc
输入两次密码
解密刚才的文件
openssl enc -d -des3 -a -salt -in /work/aaa.enc -out /work/aaa.out
openssl单向加密:
常见的有md5、sha1、sha256等,系统本身有这些工具如下图:
我们现在用openssl dest命令来实现
openssl dgst -md5 FILE
openssl非对称加密:
一般私钥用来加密公钥用来解密,但是如果要做电子签名那么就需要用私钥进行加密,公钥进行解密。最常用的是RSA。再次说明公钥不会用来进行数据加密因为速度太慢,通常用来秘钥交换和身份验证。
数字签名:
公钥加密私钥解密,我们知道数字签名不会用公钥加密数据本身,而是加密数据的特征码。常用算法RSA、DSA(只能用来做签名无法做加密)。签名本身还是加密,所以这就是说明DSA只能用公钥加密私钥解密,不能反过来。而RSA则可以。
数字证书:
为了保证公钥来源的可靠性。A有CA的公钥,B向CA申请证书且证书(里面包括B的公钥和B的信息)中包含CA的电子签名(CA私钥加密的),B把证书发给A,A用CA的公钥可以解密电子签名来验证有效性。证书格式包括:x509等。该证书里的内容包含申请者的公钥、证书过期时间、申请者的合法身份信息(地址、国家、机构名称等)、证书使用方式、CA的信息、CA的数字签名(CA私钥加密的证书前4项信息的摘要信息)
我们知道在访问电子商务网站或者银行网站的时候都是输入一个域名,你如何知道你访问的这个网站就是那个真正的网站而不是别人伪造的呢?这就是用到了ssl,这个网站都是绑定了证书,你输入的域名则包含在证书中的申请者合法身份信息中。由于客户端信任国际主要CA机构,所以为了让客户端也信任他要访问的网站,那么网站所属公司都要去CA申请证书,那私钥和公钥是谁生成的?显然这一对而私钥和公钥是申请者自己生成的(你不可能让CA给你生成,因为CA如果生成的话那就意味着CA拥有了你私钥),然后把公钥和其他必要信息发给CA,CA审核通过则颁发证书。所以你申请证书需要做的是:
自行生成一对私钥和公钥
把公钥和域名等其他必要信息按照固定格式填写并提交给CA
在以后的通讯中客户端访问网站的时候会获取该网站的证书,然后去验证合法性、之后还会查看有效期、最后还会去找CA查看该证书是否被吊销了,都检查过了以后才能安全的访问。
我们知道openssl可以生成公钥和私钥也可以建立CA,我们就从这两个方面来进行演示。两台机器
Linux01为服务器端--CA服务器
Linux02为客户端--申请证书
演示:建立CA
如果你是在企业内部小范围应用,可以使用这个工具来建立自己的CA然后给自己的服务器发放证书并管理吊销列表等操作。
构建私有CA的配置文件在/etc/pki/tls/openssl.cnf,一般无需修改,但里面的一些配置要了解。
参数 | 说明 |
dir | 如果想把openssl做成CA,那么这个CA的工作目录是哪里 |
certs | CA签发的证书放在这里,默认是相对于CA的工作目录下面的 |
crl_dir | CA吊销的证书列表放在那里 |
database | 索引文件数据库,自动生成这个文件,你通过这个文件可以快速查看有哪些证书 |
new_certs_dir |
刚刚签署的证书放在哪里 |
certificate | CA自己的证书在哪里,这里是公钥 |
serial |
当前序列号,CA签发证书的编号 |
crlnumber |
吊销证书的序列号 |
crl |
当前正在使用的CRL,证书吊销列表文件 |
private_key |
CA自己的私钥 |
RANDFILE |
随机数据文件 |
进入工作目录/etc/pki/CA,生成私钥对
通过这个命令生成私钥,公钥是通过从私钥中提取而来的。私钥的名字要和配置文件中的一样
openssl genrsa -out ./private/cakey.pem 2048 #修改权限,不是必须的,只是为了安全。 chmod 600 ./private/cakey.pem
生成证书,openssl req是一个证书申请工具,同时也可以自签名自己的证书
参数 | 说明 |
-in FILENAME |
输入文件,但是通常我们用-key |
-key FILENAME | 指定私钥文件,它会自己从私钥文件中抽取出公钥 |
-days N | 有效期限 |
-x509 | 自签名时使用的证书格式,只有自签名证书时采用 |
-out FILENAMEA |
证书放哪里,只有自签名证书时采用 |
-new |
用于一个新申请 |
openssl req -new -x509 -key ./private/cakey.pem -out cacert.pem -days 3655
cacert.pem这个也是上面那个配置文件中定义的。执行命令会开始一个向导,输入必要信息。这个信息也可以在上面那个文件中后半部分进行定义,这样就不用每次都输入了。
生成缺少的3个基本文件serial、index.txt、crlnumber,创建三个文件
touche ./index.txt serial crlnumber #有可能需要的是index.txt.attr这个文件,曾经遇到过,所以你也建立一个。
初始化serial文件,你写00也行,因为颁发证书总要有一个序号标记。
echo 01 > serial
到此CA构建完毕
演示:生成公钥和私钥对儿
我们这里演示给Nginx上的站点申请证书为例,这个证书要放在Nginx的目录中,我这里就建立一个certs的目录,然后申请证书。这个名字我叫做Nginx.pri,其实名称无所谓,长度我使用1024.
openssl genrsa -out ./Nginx.pri 1024
生成证书请求
openssl req -new -key ./Nginx.pri -out new_cacert.req
我们把生成的请求文件拷贝到CA服务器上,我这里放/tmp下了,其实放哪里都一样,最后你也要使用命令签署这个请求。
scp new_cacert.req 172.16.100.29:/tmp/
签发证书(在CA服务器上执行),然后就可以把证书拷贝会客户端服务器上
openssl ca -in /tmp/new_cacert.req -out /tmp/Nginx.crt -days 3655
SSL/TLS:
https其实就是引入了ssl或者tls。它是如何工作的呢?TCP/IP协议有四层,这四层中没有一层是加密的,那如何实现http的安全通信呢?就是在应用层和传输层中间增加了半层,它不是一整层,因为不是所有应用都需要加密,你如果增加一整层的话那所有的都加密了。
SSL是网景公司研发的,在它的浏览器和WEB服务器之间实现安全通信,它叫做安全套接子层,套接字本身就是应用层程序在内核注册的,所以在应用层和传输层中间增加了半层里面包括SSL库,如果程序调用这个库,就能够实现安全通信了。
TLS是标准化组织仿照SSL开发的,叫做传输层安全,它的机制和SSL很像,只是有些东西有变化。TLSv1和SSLv3很接近,实际应用也是常用这个2个版本。
所以应用层协议调用SSL或者TLS的就是安全通信,比如http调用后变成了https等。下面说一下最常用的https是如何实现的:
场景前提是你第一次访问淘宝网站,你要确保你访问的是真淘宝而不是仿造的,而且要保证通信是加密的安全的。
客户端打开浏览器输入淘宝网站
DNS域名解析,当得到IP地址后与该IP进行通信
和给定IP进行通信,此时将进行TCP三次握手建立会话。下面开始SSL握手
TCP连接建立之后,浏览器发起HTTPS请求,将自己支持的加密规则发送给网站,网站从中选择一组加密方式和HASH算法,然后把网站证书(证书包含公钥、数字签名和其他信息)发送给浏览器
浏览器查询证书颁发机构是否自己信任的CA机构,如果在就用CA的公钥解密证书获取证书的数字签名,如果成功解密说明证书来源可靠,然后查看证书有效期,之后去互联网上的CA查询该证书是否被吊销,如果上述任何一项没有通过就会得到一个提示,如果通过在地址栏就会出现一个绿色的锁的标志。(身份验证)
如果受信任或者用户主动选择信任,那么浏览器会生成随机密码,并用网站证书中的公钥进行加密(秘钥传递,浏览器生成的密码是对称加密用于加密通信数据)
浏览器使用之前约定好的HASH信息计算握手信息得到信息摘要,然后用生成的随机密码对握手信息进行加密,然后把摘要+加密后的握手信息+网站公钥加密后的密码发送给网站(信息加密、数据一致性)
网站收到加密后的信息,用自己的私钥解密,得到密码。然后用密码解密握手信息,然后把浏览器发来的HASH值和自己根据握手信息计算出来的HASH值对比看是否一样,如果一样证明没有被篡改。
网站使用同样的方式来加密握手信息发送给浏览器
-
SSL握手结束,开始SSL数据传输,之后所有传输的数据都是通过浏览器之前生成的那个密码来进行加密的。
注意:服务器是一般是不会验证客户端证书的,因为除非特殊情况,否是客户端都要安装客户端证书让服务器去验证。l另外为了避免遭到暴力破解,SSL会话有持续时间,超过这个时间没有请求,则自动断开,如果再想连接,则重复上述过程。
Telnet和SSH:
早期实现远程登录使用Telnet,服务器支持客户端在本地建立远程连接会话,把本来应该在服务器上显示的虚拟终端延伸至客户端来显示,早期都是物理终端,一个物理终端对应一个显卡接口和与之对应的键盘,多个用户连接就需要多个用这样的物理终端,后来就有虚拟终端,也就是只有一个显示器和显卡,但是可以显示多个登录界面,但是服务器多了不可能登录的时候都跑到服务器前去打开这个终端,所有就有了远程登录,在服务器上运行一个软件,监听在某一个端口,用来等待客户端登录连接,你要让一个用户可以看到登录界面输入用户名和密码就必须的关联到用户使用的终端上,我们知道登录界面是login的程序,它必须关联到用户的界面上才能完成,用户界面通常是一个设备,而这个设备就是一个终端设备,如果是物理终端很好解决,但是远程主机怎么办?把远程主机的鼠标、键盘和显示器关联到服务器上,由服务器解析为本地登录设备。所有就有Telnet,但是它的传输是明文,很不安全。所有就有了ssh,这个叫做Secure Shell的缩写,它监听在22号端口。
在使用SSH的场景中,通常需要使用证书,但是也不是必须的,如果没有证书如何保证你登录的服务器就是你要登录的服务器呢,你SSH登录的时候,第一次会得到一个提示,里面包含服务器的指纹信息,然后询问你是否信任这个计算机,如果你输入了YES,那么这个服务器的指纹信息就会记录到你本机的一个列表中(kNow_hosts文件)下次就不没有提示了。这就相当于是你手动的信任了这个主机,所有没有证书也可以。如果有证书就不需要手动信任了。但是过了这个阶段后面你就要输入用户名和密码进行验证,这个信息如何加密呢?其实在你看到输入登录信息之前,ssh客户端和服务器就进行了加密方法的协商,客户端生成一个一次性对称加密秘钥,然后用服务器的公钥进行加密发送给服务器,完成秘钥交换,然后客户端用加密秘钥加密用户名和密码信息发送给服务器,服务器用私钥解密得到信息后进行验证。之后彼此通信就用这个密码。但是ssh和https不同,https通信时候一段时间没有请求就会断,但是ssh则不会它会一直在线,但是这就有个问题,因为不自动断开所以如果别人捕获了你的通信进行暴力破解,一旦成功,那么它就可以使用这个密码。那怎么解决这个问题呢?很简单,随时换密码,也就是隔一段时间协商更换一次密码,但是连接不断开。在Linux上基于ssh这种协议实现的软件是openssh。
ssh认证机制:基于口令和基于秘钥,通常使用基于秘钥的。它需要的也很简单
#生成秘钥对,保存在用户家目录中的.ssh目录中,会生成2个文件,id_rsa是私钥id_rsa.pub是公钥 ssh-key -t rsa
说明:上面的密码要设置为空呢?这个密码是给私钥设置的,为了保护私钥文件,所以要设置密码,但是如果你这里设置密码的话每次使用这个私钥都得输入密码,比如当你ssh连接目标主机的时候,会用到你这个私钥,这时候你还得输入密码。所以要么不加密,要么让进程记住这个密码,比如ssh-add或者ssh-agent它会记录这些密码然后一个一个常识。
复制秘钥到远程主机
ssh-copy-id -i 公钥文件 用户@主机IP注意:这里的user是你想以哪个用户登录,实际上这个命令就是把公钥文件内容写入到目标主机的root用户家目录下的.ssh目录中的authorized_keys文件中。
openssh的服务器端程序是sshd,这里说一下它的配置文件和脚本:
服务脚本:/etc/rc.d/init.d/sshd
参数 | 说明 |
Port | 默认是22 |
ListenAddress | 监听地址,默认是所有 |
Protocal | 协议版本,默认是2 |
HostKey | 是主机秘钥,本机kNow_host里面存放的就是登录过这台主机的公钥,比如A登录B,那么A的kNow_host里面就会存放B的公钥,公钥存放位置是/etc/ssh/ssh_host_rsa_key,默认都会使用这个。 |
KeyRegenerationInterval | 我们知道主机双方通信会生成一个临时秘钥用于进行对称加密,这个密码的有效期限就是这参数定义的,默认是1小时 |
ServerKeyBits | 主机秘钥的长度 |
LoginGraceTime | 登录宽限期,密码提示符等待多久,如果期间没有输入密码,则断开连接。默认2分钟 |
PermitRootLogin | 是否允许管理员登录,默认是允许 |
StrictModes | 严格模式,除了验证用户名和密码之外,还要看你所要登录的服务器上是否有你使用的用户的家目录以及里面的权限。 |
MaxAuthTries | 认证最多尝试次数,默认6次 |
MaxSessions | 最多会话建立个数,默认10个 |
RSAAuthentication | 是否使用RSA认证,默认是YES |
PubkeyAuthentication | 是否使用公钥认证,默认是YES |
AuthorizedKeysFile | 验证所使用的文件,默认是.ssh/authorized_keys,这个文件也就是存放对方公钥的文件。 |
RhostsRSAAuthentication no | 是否允许基于远程主机的认证,也就是A和B主机互信,那么B的用户都可以登录A主机,默认是NO |
PasswordAuthentication | 是否允许输入密码来进行认证,默认是YES |
ChallengeResponseAuthentication | 是否启用挑战式握手身份认证,默认是NO |
GSSAPIAuthentication | 是否允许GSSAPI认证,默认是YES |
GSSAPICleanupCredentials | 是否清除认证过程,默认是YES |
UsePAM | 是否使用PAM认证,默认是YES |
AllowUsers |
用户白名单,就是仅允许哪些用户登录 |
DenyUsers |
用户黑名单 |
ClientAliveInterval | 客户端活动时间间隔,也就是超时时长,单位为秒。 |
ClientAliveCountMax |
客户端活动消息数量,客户端收到服务器响应之前可以发送多个个命令给服务器。 |
使用SSH的最佳实践:
仅使用SSH2版本
配置空闲会话超时时长,也就是多久不输入命令自动断开。ClientAliveInterval、ClientAliveCountMax
使用iptables设置ssh服务安全访问策略,也就是只允许哪些IP段可以访问
更改ssh默认端口号
使用强密码,足够长和复杂
使用基于公钥认证
使用暴力破解工具自己先破解一下看看
限制ssh方法频度
经常看一下日志,看看有没有人进行尝试破解
生成强密码:
#!/bin/bash genpasswd(){ local len=$1 [ $len == "" ] && len=20 #从/dev/urandom读取随机数,然后送到tr中,通过-dc参数把字符删除,然后再送到 #head -c,把里面特殊字符删除,取前20位,在用xargs处理 tr -dc A-Za-z0-9_ < /dev/urandom | head -c $len | xargs } genpasswd
#显示当前系统上每个用户账号最近一次成功登录信息、从哪个主机登录以及使用了哪个终端 lastlog lastlog -u 显示指定用户 #显示当前登录用户 whoami #显示当前系统上最近失败登录信息,其实就是搜索/var/log/btmp文件 lastb #显示当前系统上最近成功登录信息,其实就是搜索/var/log/wtmp文件 last