Identity – 安全基础知识
前言
一旦涉及到用户, 那么安全就上一个层次了.
这篇主要是说说一些安全的基础
用户密码保存
网络上有太多资料说这些基础了, 我就不拉过来了. 大致记入一些重点就好了.
- 为什么不可以明文保存
因为用户习惯一个密码到处用, 一旦我们的数据库被黑了,hacker 就可以拿密码去其它网站试. 用户把密码交给我们, 我们就必要确保它的安全性. 哪怕是被黑了, 密码也不可以被公开.
- 用什么方式保存密码
Identity 使用的保存方式是 PBKDF2, 这个也是目前比较 standard 的方案. 到处都是用这个.
它里头有 3 个概念: 哈希函数, 盐, 慢哈希.
哈希函数
哈希函数的代表是 SHA256, 早年的是 MD5. 许多地方都会用到哈希函数. 不只是保存密码.
它主要的功能就是把内容变成乱码, 另外它有 2 个特性:
- 不可逆, 乱码是无法被还原的
- unique, 不同的内容哈希出来的结果一定是不相同的,同一个内容哈希出来的结果一定是相同的.
有了特性 1, 那么我们就可以把密码哈希成乱码, 而 hacker 即使拿到乱码也无法还原成密码.
有了特性 2, 我们在验证用户密码的时候, 只需要把密码进行哈希, 然后和保存的哈希值进行比对, 就可以确定用户是否输入正确密码了.
盐
只使用哈希函数依然是不够安全的. 因为有一个东西叫彩虹表, 里面记入了各种密码的 SHA256 版本
hacker 只要拿到数据库. 然后通过与彩虹表的匹配就可以快速查出密码了, 这等于还原了密码.
为了解决这个问题, 就有了加盐的概念. SHA256(SHA256(password) + 盐) 大概长这样.
盐就是一个随机值. hacker 无法提前知道盐 (盐是随机的) 就无法做出带了盐的彩虹表, 所以彩虹表就不复存在了.
这里经常会有 3 个疑问 :
1. 盐需要保存吗 ?
需要, 因为在用户登入验证密码时, 我们必须要可以做出一摸一样的乱码来匹配.
2. 盐要保存在哪里 ?
identity 的盐就放在 PasswordHash column. 和用户资料放一起就可以了, 不需要特别分表之类的.
3. hacker 拿到盐之后是否可以做出彩虹表来破解 ?
彩虹表的特性是提前做一个笛卡尔积的密码哈希. 它的关键就是提前. 如果没有办法提前做, 那么就等于是用暴力破解了.
慢哈希
慢哈希就是用来防暴力破解的. 它其实就是不停的迭代执行哈希函数. 如果哈希需要 1 秒来完成. 那么 hacker 每试一个密码就需要 1 秒.
hacker 需要笛卡尔积试这么多密码组合, 每个需要 1 秒那就天荒地老了, 也就放弃了.
慢哈希会让用户登入也变慢. 但是影响不会太大, 所以是 ok 的.
对称加密
对称加密就是我们最常见的, 通过一个密码 (不可公开), 一个加密算法(可公开), 对一个信息加密, 然后变成乱码, 通过一个解密算法就可以还原信息.
Identity cookie 就使用到了对称加密, cookie 值都是乱码.
ASP.NET Core 的 Data Protection 就是用来做对称加密的. 里头运行的是 AES 算法.
对称加密的目的就是防窃听. 没有密钥就推倒不出密文. (密钥是很长的字符串, 很难被暴力破解的)
对比非对称加密, 对称加密的优点是快, 要加密的内容可以很大, 缺点是只有一把密钥. 如果要让接收者看到内容就必须把密钥给他, 而同时他也具备了加密的能力 (这或许并不是我们想要的)
非对称加密
非对称加密有 2 把密钥
任何 1 把加密, 另一把就解密.
一开始我们会任选出一把叫公钥,另一把就叫私钥.
公钥是可以公开给外人知道的, 私钥则只可以自己持有.
对比对称加密, 它的优点就是能把加密和解密拆分, 我加密, 你只能解密 (不能加密).
缺点是慢, 而且内容不能大. 内容的长度不能超过密钥, 密钥越长加密就越慢
非对称加密可以解决通讯的 3 大难题
1. 防窃听
使用收信人的公钥对内容加密. 这样就只有收件人可以解密看到内容,这样就确保了外人无法窃听到内容.
2. 防冒名 和 3. 防篡改
先说一下什么是 "消息摘要", 一个内容被哈希函数过变成的乱码就叫消息摘要
使用发信人的私钥对消息摘要加密 (这个就叫数字签名), 然后把内容和签名一起发出去. 收信人用发信人的公钥解密得到消息摘要, 如果解密成功就确定了发信人身份
然后拿内容做哈希得到另一份消息摘要, 对比 2 个消息摘要如果是一样的就确认了内容没有被篡改过.
这里有一个点要注意, 防窃听使用收信人公钥加密, 而签名则是用发信人的私钥加密. 所以整个过程里面是有 2 pair key (总共 4 把密钥哦)
在 ASP.NET Core 我们要做非对称加密的话会用到 X.509, 它是 RSA 算法. 有兴趣可以看这篇 ASP.NET Core – Work with X509
HTTPS 流程
HTTPS 是最能体现非对称加密的场景,
首先 server 和 client (游览器) 要通讯, 然后要防窃听
那么就需要对通信内容进行加密. 这种场景一般上就是用对称加密 (它就是用来防窃听的丫)
HTTPS 确实也是用对称加密来处理的, 但是对称加密需要双方都有密钥啊, 它们没有沟通过又怎么会有相同的密钥呢 ?
这个对称加密的密钥是游览器随机创建的, 并且在第一次加密通讯中传递给服务器 (这个过程叫握手)
而这个第一次的加密通讯使用的是非对称的加密而不是对称加密. 这就是关键了
首先游览器向服务器要求服务器的公钥 (用于第一次通信的加密, 非对称加密是使用收信人公钥来做加密的, 上面有讲过了)
这时游览器就有了公钥...等等这个公钥安全吗 ? 怎样确定这个公钥就是 server 的, 可能第一次通信就被掉包了丫...
这里就需要引入一个新概念叫数字证书了.
服务器要发布公钥可不简单 (以前还需要付费呢). 首先服务器需要向一个 CA 机构申请证书. CA 机构有 2 把密钥. CA 的公钥是 pre install 在 OS 里头的 (这个是关键哦)
当服务器把公钥发给 CA 机构之后, CA 机构用私钥做签名(上面有讲过签名了) 然后给回服务器 (这个东西就叫证书)
所以当游览器向服务器要公钥时,服务器返回的是证书 (公钥 + CA 的签名)
游览器用 CA 的公钥解密 (游览器有 CA 公钥因为它是 pre install 在 OS 里的), 验证签名后, 就可以确定内容是证实的了. 内容里面有 domain 等等服务器信息
如果内容不匹配 (比如 domain 和要访问的地址不一致) 那么游览器就会给用户提示.
如果一致的话,那么就拿公钥去加密对称加密的密钥然后发给服务器
服务器收到后就用私钥解密就得到了对称加密的密钥了. 往后的沟通就用这个密钥加密就 ok 了.
OAuth JWT 中的签名
还有一个比较有名的非对称加密场景就是 JSON Web Token
由于 resource server 需要确定 JWT 是由 autho server 签发的. 所以需要做一个身份确认.
和 HTTPS 有点像,首先 resource server 去和 autho server 要公钥 (要验证签名就需要发信人的公钥) 这个过程叫 discover
和 HTTPS 不同的是这里不需要什么 CA 机构, 因为这个通信是已经建立在 HTTPS 基础之上了.
有了 HTTPS 的知识,去理解 JWT 就容易很多了。
Key Rotation
密钥要定期更换, 我们知道东西放久了就难免有疏忽的时候, 所以最好的情况是久不久就换一个新 key
我们拿 ASP.NET Core Data Protection 来举例.
假设我们 3 个月换一次密钥. 替换当天, 所有新的 cookie 都会用新的密钥加密.
而解密则是新的旧的都会尝试, 所以并不可以直接把旧的密钥给丢了哦. 丢了你就没办法解密之前加密的内容了.
非对称加密也是一样的道理. 所以在使用 OAuth 库的时候 (IdentityServer4, OpenIddic) 都是可以 fill in 多个 key 的, 就是让我们搞 key rotation 或者叫 key rollover 的.
是加密的 key 可以换, 不是签名可以换哦.
Token Self-contained or Reference
这里的 token 可以指 OAuth 的各种 token 也可以指 Identity cookie.
reference 的意思是 token 本身并没有任何有用的资料, 它只是一个 Id, 需要通过去数据库拿才可以获取到有用的资料.
这种做法的好处就是 token 轻, 安全, 数据总是最新的. 坏处就是频密的访问数据库.
为了减少数据库的访问让性能快一些 (尤其是 OAuth 的情况, 可能还需要通过 API 来访问而不是直接连数据库, 效率会更慢)
于是就有了 self contained 的概念. 也就是把一堆的 claim 放到 token 里头, 使用加密解密的方式确保内容安全.
这个做法最大的缺点就是无法立刻摧毁一个 token, 只要 token 在有效期内, 那么它就一定有效. 这也是为什么 access token 时间一般上都很短.
比如 identity cookie 就是 self contained 的, 它默认 check valid 是 30 分钟, 超过 30 分钟就去检查 securitystamp 是否有修改, 有的话就不 valid 了.
但在 30 分钟内, 你无法改变或注销这个 cookie 的权限.
OIDC 和 OAuth
我刚开始接触 OAuth 的时候它就是 2.0 了, 现在估计也没有人用 1.0 了吧. 我所知道的是 2.0 是一定要走 HTTPS 的, 而 1.0 可以不需要的 (据说 2.0 没有 HTTPS 的话, 安全程度还输给 1.0 没有 HTTPS 哦)
早年也是没有 OIDC (Open ID Connect) 的, 我们用 OAuth 来获取用户数据. 没有 identity token 这个东东, 只有 access token 和 refresh token. 好, 进入正题
OAuth 2.0
OAuth 最早的用法是 external login, 比如用 Facebook account 去注册其它网站.
抽象一点讲就是让 Facebook 的用户授权给某网站, 允许访问用户在 Facebook 的资料
这个过程是用户 A 到了网站 B 然后跳转到 Facebook 做一个 login + 允许授权 (依据网站 B 要求的权限) 用户允许后就跳转回网站 B, 这时网站 B 就可以访问到用户 A Facebook 的信息了 (甚至是 添加, 修改, 删除, 依据授权的范围)
早年我们一般是属于网站 B 这个的角色. 随着前后端分离. 手机也好, web app 也要. 我们就扮演起了 Facebook 这个角色. 让我们来理一下这个关系和它们对应的名称.
Facebook login + 授权网站 = autho server
user = 我们网站的用户
网站 B = 我们的手机 app / web app = client
Facebook 资料网站 = 我们的 web api server = resource server
虽然感觉有一点点大材小用, 但是现在前后端分离确实就是这样搞的. 自己的用户在自己网站的 login page 授权给自己的 web app 去访问自己的 API...
OAuth 有几个比较有名的 flow
1. client credentials
它是用于 server to server 的, client 需要 client id + client secret 就可以通过 autho server 获取到 access token 去访问 Web API 了.
这个跟用户没有任何关系, 通常用于非常信任的 client
另外需要注意的是 client secret 是不可以外泄的哦, client secret 只能出现在 server 端而且要用 azure key vault 来保护 (它属于这种级别)
2. implicit
这个是一种很轻量的方式, 使用的场景我没有遇过
猜测就是那种需要用户短暂授权的 web app. 这种 flow 是不需要 client secret 的, 它也只返回 access token 不会有 refresh token
如果我有一个 web app 让用户 export 图片, 那么就可以用这个 flow 咯
3. password
这个也是很奇葩的模式, 直接使用用户密码来登入...我猜不出场景
4. authorization code
这个就是最常用的 flow 了, 好好说说这个呗 (前后分离基本上也是用这个 flow 只是在做了一些修改而已)
我用回 B 网站和 Facebook 的例子
首先 B 网站需要向 Facebook 申请成为 client, 那么 B 网站 就有了 client id 和 client secret, 而 Facebook 也记入了这个 client 的资料和 redirect url (这个挺重要的哦)
B 网站首先把用户 redirect 到 Facebook, 附上 client id, scope (要求授权的范围), redirect url (必须和申请的时候一致), state(一个随机数, 等下 Facebook 会原封不动返回这个 state)
到了 Facebook, 用户就 login 授权. 这时 Facebook 就会 redirect 用户到 client 的 redirect url. 并且附上一个 code 和刚才的 state
在网站 B 的后端, 确认一下 state (要确定是我们发出去的申请), 然后拿 code + client secret 去 Facebook 换取 access token 和 refresh token
从现在开始就可以用 access token 去访问 Facebook 资料了.
通过 refresh token 我们可以一直保持 access token active 直到 refresh token 到期为止.
上面这个 flow 并不完全适合做前后端分离的 web app, 因为 web app 是没有后端的, 没有后端就不可以有 client secret. 上面也就无法搞下去了.
所以后来就有了多一个 flow
5. authorization code + PKCE
refer:
PKCE 的关键就是要解决掉 client secret 的问题. 它的思路就是搞一个临时密码.
我自己有一个不清楚的是...中间人拦截了又怎样呢, 我都 HTTPS 了他应该什么也看不到吧....搞不明白
这里我想提一下关于 autho server 和 client 需要注意的安全 (虽然一般 OAuth 的库都会帮我们搞定好一切)
autho server 最重要的是只能把 code 交给正确的 client, 所以一定要使用数据库里面 client 注册的 redirect url
autho server 在发送 access token 时会需要 client secret 的原因是双重保证. 按理说只有 client 能拿到 code, 和 refresh token
那么只要有 code 和 refresh token 就 ok 了的. 但是如果 refresh token 不小心弄丢了, 那就很麻烦了. 所以为了双重保险使用 client secret 就安全一点, 即使 refresh token 丢了.
对方也不一定有 client secret 哪怕有, 我依然可以换掉我的 secret 来让 refresh token 不 valid. 所以能用 secret 的时候就尽量用呗.
Silent Authentication and Refresh Token Rotation
早些时候 web-based 是用 silent authentication 的, 通过 iframe 来做登入. 但后来
所以目前最佳实践是 Refresh Token Rotation, 就是每一次请求 refresh token 就会拿到新的 refresh token.
另外, 这个 rotation 机制也需要担心 concurrency 问题, 比如在 OpenIddict 默认允许 30秒内, 旧的 refresh token 依然有效.
OIDC (Open ID Connect)
了解了 OAuth 再去了解 OIDC 就简单多了.
如果 OAuth 是授权, 那么 OIDC 就是 authen, 由于 autho 一定要先 authen 所以大家就认为有 autho 就好了丫.
但后来大家发现 external signin 其实不能算是授权. 因为如果我只是单纯要求用户使用 Facebook 登入替代密码的话, 我并没有需要任何 Facebook 的资料丫.
所以后来就有了 authen 的概念. 然后又有了 identity token 概念 (用来直接解析出用户信息)
我觉得这样其实挺好的.
JOSE (JWT, JWS, JWE, JWK)
refer:
与 JOSE 战斗的日子 - 写给 iOS 开发者的密码学入门手册 (基础)
The benefits of JWT + JWS + JWE on API Designs
JSON Web Encryption (JWE) in .NET Core
JWT, JWS and JWE for Not So Dummies
其实, 每次我们说 JSON Web Token (JWT) 讲的是 JSON Web Signature (JWS) 来的
整个 JW 体系是很大的, 叫 JOSE (Javascript Object Signing and Encryption)
我是因为看到关于 JWT payload 加密才一路找过去的. payload 以前是没有加密的. 只是提倡说不要把敏感数据放进去.
但近年来视乎越来越多人会往 payload 放一些权限的资料 (为了 self contained 减少请求, 提高效率嘛) 所以就开始要加密了咯.
JWT 和 JWS 算是继承关系,但是由于大家叫惯了所以可以把它们看成是一样的.
JWE JSON Web Encrypt 就是加密 payload 了.
这里加密的目的是防窃听, autho server 加密, resource server 解密. 通常看到这种情况就少不了对称加密 + 非对称加密一起上了 (原来这还有个名称叫 key wrapping)
如果 autho server 和 resource server 是同一台的话, 是可以只用对称加密的.
这里需要注意, 非对称加密用于防窃听是用收信人的公钥来加密的, 在这里就是说 autho server 需要有 resource server 的公钥才能加密 token.
refer: OAuth Access Token Implementation
这里我有一个比较不太能理解的地方是. 如果我有不同的 resource server 那么该怎么办呢 ? 难道所有的 resoruce server 共享一对公钥私钥吗 ? 还是我不应该有多个 resource server 呢 ?
这里留个悬念以后搞明白了再回来看看, 毕竟目前项目是 autho resource server 在一起的. 并不会遇到这些问题.
JWT 要保存在 Local Storage or Cookies?
refer:
LocalStorage vs Cookie for JWT Access Token war in short
Where to Store your JWTs – Cookies vs HTML5 Web Storage
Auth0 Browser local storage scenarios
绝大部分的教程都是通过 header bearer 传 access token 的. 但说到安全, 大部分教程会说把 access token 保存在 cookies.
理由就是当被 XSS 攻击时, local storage 里的 access token 会被直接拿到手, 而在 cookies HttpOnly 的 access token 没办法被获取.
所以在已经被 XSS 攻击的情况下, cookies 是比较安全的.
虽然说比较安全,但是也是要看看性价比和风险, 抉择值不值的这样做.
我个人是觉得这个保护意义并没有很大, 因为已经被 XSS 了, 攻击者已经可以伪造任何授权请求了. 你只是让它没有能力去把这个 access token share 出去而已.
cookie 的缺点是它会有 CSRF, 虽然你可以通过 random string + cookies + header 去防范. 但是那也是一个成本丫.
当你的 resource server, web app, authentication server 是分开 domain 的情况下. 你的 cookies 会变得更难实现.
Identity – 安全基础知识的更多相关文章
- SQL server基础知识(表操作、数据约束、多表链接查询)
SQL server基础知识 一.基础知识 (1).存储结构:数据库->表->数据 (2).管理数据库 增加:create database 数据库名称 删除:drop database ...
- [SQL]SQL Server数据表的基础知识与增查删改
SQL Server数据表的基础知识与增查删改 由张晨辉(学生) 于19天 前发表 | 阅读94次 一.常用数据类型 .整型:bigint.int.smallint.tinyint .小数:decim ...
- Data Base sqlServer基础知识
sqlServer 基础知识 大纲 创建数据库 1 创建表 2 备份表 3 删除表 4 修改表 5 查询出重复的数据 6 增删改查 7 添加约束 8 分页存储过程 9 排序 10 类型转换 11 ...
- 【OGG】OGG基础知识整理
[OGG]OGG基础知识整理 一.GoldenGate介绍 GoldenGate软件是一种基于日志的结构化数据复制软件.GoldenGate 能够实现大量交易数据的实时捕捉.变换和投递,实现源数据库与 ...
- 基础知识(C#语法、数据库SQL Server)回顾与总结
前言 已经有大概一个多月没有更新博客,可能是开始变得有点懒散了吧,有时候想写,但是又需要额外投入更多的时间去学习,感觉精力完全不够用啊,所以为了弥补这一个多月的潜水,决定写一篇,衔接9月未写博客的空缺 ...
- sqlServer基础知识
sqlServer 基础知识 大纲 创建数据库 1 创建表 2 备份表 3 删除表 4 修改表 5 查询出重复的数据 6 增删改查 7 添加约束 8 分页存储过程 9 排序 10 类型转换 11 ...
- openstack学习笔记(一)-openstack的基础知识
一.OpenStack的基础知识 openstack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的,以Apache2.0许可证(兼容GPLv3以及DFSG)授权的自由软件和 ...
- 开发技术--浅谈python基础知识
开发|浅谈python基础知识 最近复习一些基础内容,故将Python的基础进行了总结.注意:这篇文章只列出来我觉得重点,并且需要记忆的知识. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对 ...
- 常见SQL语句和SQL基础知识
引自:http://blog.csdn.net/u012467492/article/details/46790205 SQL语句考察(一) 1.查询出每门课都大于80 分的学生姓名 name k ...
- JAVA相关基础知识
JAVA相关基础知识 1.面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分, ...
随机推荐
- 【干货】顶级 Java 源码教程项目大汇总!
大家好,我是鱼皮,今天分享几个 GitHub 上顶级的 Java 源码教程项目. 区别于书籍.文档.视频等形式的教程,这些项目几乎都是由 精简的代码片段 和 Demo 组成的,能够轻松地在本地执行,非 ...
- Python 使用Python操作xmind文件
使用Python操作xmind文件 by:授客 QQ:1033553122 测试环境 Win10 Python 3.5.4 XMind-1.2.0.tar.gz 下载地址: https://fil ...
- java面试一日一题:讲下ThreadLocal
问题:请讲下ThreadLocal 分析:首先要了解ThreadLocal的基本原理:其次要理解ThreadLocal发生内存泄漏的原因:最后ThreadLocal是如何做到线程隔离的 回答要点: 主 ...
- 【Java】JDBC Part5 DataSource 连接池操作
JDBC Part5 DataSource 连接池操作 - javax.sql.DataSource 接口,通常由服务器实现 - DBCP Tomcat自带相对C3P0速度较快,但存在BUG,已经不更 ...
- 【Vue】接口模块化处理
在前端Vue项目中,接口会被统一放在一个目录中管理: 一个模块的所有接口放在一个JS文件中: 文件会导入封装好的请求方法,和动态绑定的接口地址 import request from '@/utils ...
- 英语表达中address和solve的区别
"Address" 和 "solve" 都表示处理问题,但在具体用法和含义上有所不同: Address: 含义: 处理.应对.讨论或提及问题. 强调: 关注并开 ...
- ChatGPT的训练费用以及成功原因
参考: https://baijiahao.baidu.com/s?id=1772914234034992726&wfr=spider&for=pc ================= ...
- 【转载】 MPP大规模并行处理架构详解
本文来自博客园,作者:五分钟学大数据 原文链接:https://www.cnblogs.com/itlz/p/14998858.html =============================== ...
- CF506D题解
Mr. Kitayuta's Colorful Graph 算法:根号分治. 题目大意先说一下:给一个 \(n\) 点 \(m\) 边的无向图,边有颜色.\(q\) 组询问,每次给出 \(u,v\), ...
- grpc断路器之sentinel
荐
背景 为了防止下游服务雪崩,这里考虑使用断路器 技术选型 由于是springboot服务且集成了istio,这里考虑三种方案 istio hystrix sentinel 这里分别有这几种方案的对比 ...