①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳✕✓✔✖
登陆不仅仅使用用户名登陆,还会涉及到很多登陆方法。例如:
OTP
动态口令下面介绍常用的设计方法与组建。
参考文档
二次认证组件:j256/two-factor-auth
2FA
使用了基于时间的一次性密码(TOTP)算法,可以结合Google Authenticator
移动应用程序、可认证的移动端或者浏览器一起使用。
Spring 的例子用到了这个组件,所以花了点时间研究一下这个组件的功能。
下面是从官网中翻译的,其中【使用方式 1】不是太明白,感觉直接将密钥用二维码传递,会不会泄漏机密呀?
使用方式 1
generateBase32Secret()
产生一个 base-32 密钥. 例如: "NY4A5CPJZ46LXZCP"
。qrImageUrl(...)
可以返回一个二维码 URL 地址,这里有一个GoogleAPIs
的例子。如果 Google 不好用,可以选择国内的或者自己做一个。使用方式 2
generateCurrentNumberString(密钥)
做对比。上面的文章写的很明白。
第一步,用户开启双因素认证后,服务器生成一个密钥。
第二步:服务器提示用户扫描二维码(或者使用其他方式),把密钥保存到用户的手机。也就是说,服务器和用户的手机,现在都有了同一把密钥。
第三步,用户登录时,手机客户端使用这个密钥和当前时间戳,生成一个哈希,有效期默认为 30 秒。用户在有效期内,把这个哈希提交给服务器。
基于 Base32
函数名 | 说明 |
---|---|
generateBase32Secret | 生成密钥 |
generateCurrentNumberString | 根据密钥生成数字字符串 |
generateNumber | 根据密钥生成数字,可以指定的参数: 1:密钥 2:当前的时间(可选) 3:间隔时间,默认 30 秒(可选) 4: OTP 的 digits(可选) |
validateCurrentNumber | 验证当前的数值可以指定的参数: 1:密钥 2:数值 3:当前的时间 |
基于 Hex
函数名 | 说明 |
---|---|
generateHexSecret | 生成密钥 |
generateCurrentNumberStringHex | 根据密钥生成数字字符串 |
generateNumberHex | 根据密钥生成数字,可以指定的参数: 1:密钥 2:当前的时间(可选) 3:间隔时间,默认 30 秒(可选) 4: OTP 的 digits(可选) |
validateCurrentNumberHex | 验证当前的数值可以指定的参数: 1:密钥 2:数值 3:当前的时间 |
其他辅助
函数名 | 说明 |
---|---|
qrImageUrl | 得到二维码的 Urlhttps://chart.googleapis.com/chart 国内无法访问 |
generateOtpAuthUrl | 得到 otpauth 的 Urlotpauth://totp/ 国内无法访问 |
是这个公司https://connect2id.com/提供的开源组件,在Spring中被广泛使用,用来生成或校验jwt Token。
参考网址:
ssh-keygen
命令 用于为“ssh”生成、管理和转换认证密钥,它支持RSA
和DSA
两种认证密。SSH 密钥默认保留在 ~/.ssh
目录中。 如果没有 ~/.ssh
目录,ssh-keygen
命令会使用正确的权限创建一个。
命令语法
ssh-keygen [选项]
命令选项
示例
以下 ssh-keygen
命令默认在 ~/.ssh 目录中生成 4096 位 SSH RSA
公钥和私钥文件。 如果当前位置存在 SSH 密钥对,这些文件将被覆盖。
ssh-keygen -m PEM -t rsa -b 4096
使用ssh-kengen
会在~/.ssh/目录下生成两个文件,不指定文件名和密钥类型的时候,默认生成的两个文件是:
id_rsa
第一个是私钥文件id_rsa.pub
第二个是公钥文件指定秘钥文件路径
ssh-keygen -t rsa -C 'rumenz@qq.com' -f ~/.ssh/github_id_rsa
java 使用的是 pkcs8 格式,所以要用 java 读取私钥文件,就必须转换成 PKCS8 格式。 公钥没关系,因为公钥都是 pkcs8 格式。
不管是 pkcs1 或 pkcs8 格式的私钥,导出的公钥都一样。
也有人推荐:LibresSSL。
# 版本号openssl version# 生成私钥openssl genrsa -out app_private_key.pem 2048# 私钥转为PKCS8格式openssl pkcs8 -topk8 -inform PEM -in app_private_key.pem -outform PEM -nocrypt -out app_private_key_pkcs8.pem# 生成公钥openssl rsa -in app_private_key.pem -pubout -out app_public_key.pem
2.数据签名 数据签名的作用是防止数据被篡改(或者说篡改了能被发现) RSA 数据签名的过程如下: (1)B(一般是客户端)生成一对公私钥,私钥 B 自己保留(一般要求安全存储),不对外公开,公钥公开,通常随数据一块发送给对端; (2)B 使用自己的私钥对源数据的摘要加密(因为摘要是唯一且不可逆的,摘要值不变,说明数据也没变,就形成了签名,B 将源数据和签名一起发送给 A; (3)A 收到数据和签名后,使用同样的摘要算法进行摘要计算,并使用 B 给的公钥对公钥对签名值解密,若解密后的摘要值与 A 端计算的摘要值一致,则说明数据没被篡改; 这个过程中,如果黑客截获了数据和 B 发给 A 的公钥,以及数据签名,但由于只有使用私钥才能对数据进行签名,因此黑客没办法伪造数据和其签名值,因此能防止信息被篡改。但因为数据本身是明文,因此信息会被泄露。
那么没有既防止信息泄露又防止数据被篡改的方法呢,答案就是同时使用加密和签名,但通常使用非对称算法进行加密,资源消耗会远大于对称算法进行加密。
Ubuntu 系统使用 openssl 进行 RSA 加密/解密/签名/验签
openssl genrsa -out rsa_private_key.pem 2048
参数:genrsa 生成密钥
- -out 输出到文件 rsa_private_key.pem 文件名 2048 长度
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
参数 rsa
- -in 从文件中读入 rsa_private_key.pem
- -pubout 输出公钥
- -out 到文件 rsa_public_key.pem 文件名
openssl rsautl -encrypt -in readme.txt -inkey rsa_public_key.pem -pubin -out hello.en
参数 rsautl 加解密
- -encrypt 加密
- -in 从文件输入 readme.txt 文件名
- -inkey 输入的密钥 rsa_public_key.pem 上一步生成的公钥
- -pubin 表名输入是公钥文件
- -out 输出到文件 hello.en 输出文件名
openssl rsautl -decrypt -in hello.en -inkey rsa_private_key.pem -out hello.de
参数 rsautl 加解密
- -decrypt 解密
- -in 从文件输入 hello.en 上一步生成的加密文件
- -inkey 输入的密钥 rsa_private_key.pem 上一步生成的私钥
- -out 输出到文件 hello.de 输出的文件名
openssl rsautl -sign -inkey rsa_private_key.pem -in readme.txt -out hello.sign
参数 rsautl 加解密
- -sign 签名
- -inkey rsa_private_key.pem 使用私钥
- -in readme.txt 要签名的文件
- -out hello.sign 签名
openssl rsautl -verify -inkey rsa_public_key.pem -pubin -in hello.sign -out hello.unsign
参数 rsautl 加解密
- -verify 验证
- -inkey rsa_public_key.pem 使用公钥
- -pubin 表名输入是公钥文件
- -in hello.sign 要验证的内容
- -out hello.unsign
有时候,为了安全,需要对私钥进行加密
openssl genrsa -aes256 -passout pass:123456 -out rsa_aes_private.key 2048
- -aes256 加密的方法
- -passout pass:123456 输出密码到加密算法中
openssl rsa -in rsa_aes_private.key -passin pass:123456 -pubout -out rsa_public.key
这个私钥是带有密码的,所以要输入参数
- -passin pass:123456
openssl rsautl -encrypt -in readme.txt -inkey rsa_public.key -pubin -out hello.en
由于公钥没有加密,所以这里不需要密码
openssl rsautl -decrypt -in hello.en -inkey rsa_aes_private.key -passin pass:123456 -out hello.de
这个私钥是带有密码的,所以要输入参数
- -passin pass:123456
openssl rsa -in rsa_aes_private.key -passin pass:123456 -out rsa_private.key
openssl rsa -in rsa_private.key -aes256 -passout pass:111111 -out rsa_aes_private.key
openssl rsa -in rsa_private.key -noout -text
输出的内容比较多,这里不显示
openssl rsa -in rsa_public.key -pubin -noout -text
输出内容是
RSA Public-Key: (2048 bit)Modulus:00:d0:b2:68:23:b9:16:a6:b4:11:d1:ad:7d:ba:c7:26:73:6e:ef:13:69:68:d3:43:09:c3:f1:3e:9d:4e:9e:d4:91:aa:5e:a3:da:df:ed:d7:1e:83:e6:87:64:32:96:24:5d:74:ab:66:22:96:12:f5:30:c4:60:f0:88:33:a8:dc:10:45:9c:d3:76:44:60:d6:83:9b:8a:5b:7b:c0:1a:dc:f5:2e:6e:07:bc:3a:6d:f2:26:4b:1f:91:92:8d:e2:cd:f4:30:46:e0:28:08:94:ab:bc:3a:87:c4:dd:de:af:bf:c1:d5:58:f1:1c:a7:9f:f3:12:0d:aa:c8:66:09:f3:70:ed:4b:ef:35:52:50:48:de:70:9a:cc:cb:66:64:ad:cb:30:16:d2:23:67:e7:82:7d:44:d1:a4:f7:a5:ef:00:5a:a1:52:35:03:e7:97:0c:02:f6:0b:f4:ae:38:39:68:51:d3:30:6e:0f:95:70:07:c8:14:84:e6:99:76:59:99:69:2d:8d:b9:80:c5:e6:01:b3:8d:5e:5c:47:d7:35:a1:c2:dc:1d:c5:b1:6f:65:ff:0a:0d:87:f7:cd:ca:9d:75:6e:25:7e:f5:96:03:03:30:35:7e:86:c8:c2:f4:55:06:16:93:66:0e:1e:d8:60:48:ad:d2:c0:4f:e3:16:45:23:96:cdExponent: 65537 (0x10001)
可以参考openssl 自签名证书
1.生成 CA 证书的私钥 key(ca.key)。以下输入了为这个 key 值设置了密码,且密码使用 aes128 加密保存:
openssl genrsa -aes128 -out ca.key 2048# 这个key文件就是私钥文件,可以查看文件内容:cat ca.key
2.生成公钥
openssl rsa -in ca.key -pubout -out ca-public.key#查看这个公钥:cat ca-public.key
3.生成 CA 的自签名证书 ca.crt
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
查看自签名证书信息(颁发者):
openssl x509 -in ca.crt -subject -issuer -noout
上面的做法,省去 csr 步骤。
nginx 官方文档中有关自签名证书的生成步骤:
cd /usr/local/nginx/confopenssl genrsa -des3 -out server.key 1024# 生成请求证书openssl req -new -key server.key -out server.csrcp server.key server.key.org# 去掉了密码openssl rsa -in server.key.org -out server.keyopenssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Configure the new certificate into nginx.conf:
server {server_name YOUR_DOMAINNAME_HERE;listen 443;ssl on;ssl_certificate /usr/local/nginx/conf/server.crt;ssl_certificate_key /usr/local/nginx/conf/server.key;}
Restart Nginx.
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 36500 -out cert.crt
req 是证书请求的子命令
- -newkey rsa:2048
- -nodes 表示私钥不加密,若不带参数将提示输入密码;
- -keyout private_key.pem 表示生成私钥(PKCS8 格式)
- -x509 表示输出证书
- -days36500 为有效期
系统会出现提示信息,可以输入:
Generating a RSA private key....................+++++.+++++writing new private key to 'rsa_private.key'-----You are about to be asked to enter information that will be incorporatedinto your certificate request.What you are about to enter is what is called a Distinguished Name or a DN.There are quite a few fields but you can leave some blankFor some fields there will be a default value,If you enter '.', the field will be left blank.-----Country Name (2 letter code) [AU]:CNState or Province Name (full name) [Some-State]:BeiJingLocality Name (eg, city) []:HaiDianOrganization Name (eg, company) [Internet Widgits Pty Ltd]:pku.edu.cnOrganizational Unit Name (eg, section) []:StudentCommon Name (e.g. server FQDN or YOUR name) []:pku.edu.cnEmail Address []:fanhl@pku.org.cn
此时就生成了:未加密码的私钥
rsa_private.key
和 CA 自签名证书cert.crt