今年至少有六个月的时间在和密码学,安全,隐私上的事情打交道,很有必要为今年总结一篇收官之作,整篇文章会描述一些基础概念,以及我力所能及的一些理解,这份知识很有可能不准确,主要让前端的同学们有一些概念,知道有这么回事,大佬轻拍;
密码学浅识
在密码学的世界里加密之前的消息被称为明文 plaintext,加密之后的消息被称为密文ciphertext,如果一段密文需要被解密再阅读,这个过程被称之为 decrypt,反之一段plaintext 需要被加密,这个过程被称之为 encrypt。那么在处理这些问题的过程(解决加密/解密的步骤)通常被称之为 算法,加密算法和解密算法被组合起来叫 密码算法。
目前我个人所接触到的主要是:
- 对称密码
- 单向散列函数
- 非对称密码
- Web Crypto API
其中对于公钥证书的数字签名等等。别着急,这些概念性的内容可能会非常的枯燥,因此我并不会描述很多,反而从实际性的问题出发,举例在前端的领域中,上述三个方向上着重解决什么问题。
- https://code.google.com/archive/p/crypto-js/
- https://github.com/brix/crypto-js
- https://github.com/PeculiarVentures/PKI.js
- https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Crypto_API
对称密码
比较典型的如 AES ,它是指在加密和解密的过程中使用同一个 密钥 的处理这个过程。我们知道,目前在中国大陆的Web世界中(不仅是Web也包括App),二维码的流行程度几乎很多场景里都有使用,这种不经过网络的直接获取数据,非常适合使用这种对称加密/解密的方式来传输数据,前端这边会使用 crypto-js 来处理 AES,这个 Google 开源的库支持 AES-128,AES-192,AES-256:
- import * as CryptoJS from "crypto-js";
- export function aesDecrypt(text, originKey){
- const bytes = CryptoJS.AES.decrypt(text, originKey);
- return bytes.toString(CryptoJS.enc.Utf8);
- }
- export function aesEncrypt(text, originKey){
- const c = CryptoJS.AES.encrypt(text, originKey);
- return c.toString();
- }
单向散列函数
这个函数如果要举例的话比较典型的有我们下载任何软件包时同时会校验一下MD5值来防止下载的软件包是一个被篡改的软件包。单向散列函数就是为了计算散列值而准备的函数,crypto-js包中不仅提供了 md5,hmac 也有 sha256 。如果有一天前端和服务端约定要对数据进行校验,当然最简单的方式是 md5 ,但这已经是一种不安全的计算了,最好使用 sha256:
- import * as CryptoJS from "crypto-js";
- const sha256 = CryptoJS.algo.SHA256.create();
- sha256.update("Message Part 1");
- sha256.update("Message Part 2");
- sha256.update("Message Part 3");
- const hash = sha256.finalize();
非对称密码
密码学的那本书里讲了很多密钥分配的问题,这种思考确实...很烧脑,不过这种前辈经历过的思考,在我们的实际应用中其实会有一个很有趣的过程。非对称密码,就是将密钥分了两个部分:加密密钥和解密密钥,发送者使用加密密钥对消息进行加密,接收者使用解密密钥进行解密。在这里加密密钥是可以被公开的,只有解密密钥是绝对不能被公开的。那么这其中使用了什么样的算法来生成密钥对(说实话,我也不是很清楚,因为没看懂),但前端的同学们了解到非对称密码还是很有必要。对于加密密钥它被称之为 `public key`,对应的解密密钥被称之为 `private key`,目前被广泛使用的公钥密码算法叫做 `RSA`。
除了加密之外,非对称密码还可以解决身份认证的问题,想一想如果有人伪装了一个和你一样的微信,同样的头像和昵称,同样的说话语气,诈骗集团极有可能因此从你处获取到真正的经济利益。因为非对称密码的公钥是可以公开的,一个人对应一个公钥,在密码的世界里,根本无法伪装,因为无法解密也无法得到认证。
我想如果你会写 Web 版的区块链钱包或者钱包,非对称密码的使用频率还是相当高的,除此之外它所在的场景会特别的特殊(前端而言),不过如果在其他的领域,会比较常见。
Web Crypto API
Web Crypto API 为脚本提供加密了一套关于密码(学)的接口,以便用于构建需要使用密码的系统。这套API的基础特性是允许在脚本中使用和维护密钥的存储,但是不允许使用JavaScript访问这些密钥本身。
Web Crypto API 必须在 HTTPS 网页中才能被使用(Chrome)
这套接口允许脚本使用以下功能:
- digest, 摘要,即计算数据块hash的能力,用于检测数据的变动。
- mac, 计算消息验证码的能力。
- sign and verify, 对文档进行数字签名和验证的能力。
- encrypt and decrypt, 对文档进行加密和解密的能力。
- import and export, 导入和导出密钥的能力。
- key generation, 产生密码学中使用的私钥或者密钥对的能力,不使用base key,而是使用本地系统的能力。(the ability to create a cryptographically secure key, or key pair, without the use of base key, but using the available entropy of the local system.)
- key wrapping and unwrapping, 密钥包裹和解包,即在不接触底层密钥内容的情况下,与第三方传送、接收使用另一个密钥加密后的密钥的能力。
- random, 生成密码学中使用的伪随机数的能力。
使用 Web Crypto API 的原因是我所使用的 PKI.js 依赖了 Web Crypto API 。
PKI(Public Key Infrastructure)是一个用非对称密码算法原理和技术来实现并提供安全服务的具有通用性的安全基础设施,是一种遵循标准的利用公钥加密技术为网上电子商务、电子政务的开展,提供一整套安全的基础平台。PKI,公钥基础设施,顾名思义,PKI技术就是利用公钥理论和技术建立的提供网络信息安全服务的基础设施。PKI管理平台能够为网络中所有需要采用加密和数字签名等密码服务的用户提供所需的密钥和证书管理,用户可以利用PKI平台提供的安全服务进行安全通信。
安全
前端的安全性问题大体上都可归结为 浏览器安全问题,Node.js 可以归纳为另外一个领域。浏览器安全问题 又可以细分出来很多问题,比较常见的如:XSS,CSRF,这些问题看似离我们很远,因为目前我们使用的框架基本上辅助我们已经处理了这些问题,但是整个 Web 世界中还有更多更多我们还未触及的问题(对于此我也是一个小白),比如:HTTPS 与中间人攻击,定制浏览器的扩展和插件漏洞,目前我主要关注的点在 定制浏览器的扩展和插件漏洞 这一块,这个事情因为和我在处理的问题息息相关,但又和传统的 Web 安全问题有了显著的区别:
- 权限更高的 API
- Content Script 劫持
- 中间人攻击
- 各种“内核”级别的攻击
归纳起来对于权限的授权,我们应该只申请本插件只使用的 API ,千万不可使用 * 或all_url 的形式,对于 CS 被劫持的问题,可以给网页注入的内容添加一个哈希运算,比如前面我们用到的单向散列函数来进行计算。
安全是一个特别综合性的体系,单一的前端技能可能在这上面能发挥的认知会比较有限,这里的认知 意味着同样的一件事情,安全工程师能从这里了解到前前后后可能出现的问题。
举个例子:我们都知道 location 可以获取 URL 上的各种参数,其实如果黑客利用URL中的某些关键信息伪造了一个钓鱼网站,用户是极容易中奖的。
另外一个典型的 CSRF 问题,有着比较复杂的流程,但是它利用的还是浏览器中处理 cookie 的机制:
- 受害者登录 a.com,并保留了登录Cookie
- 攻击者引诱(黄色网站)受害者访问 b.com
- b.com 向 a.com 发送一个请求 a.com/xxx=123,根据浏览器处理 Cookie 的机制,此时发起的请求会携带a.com 的 Cookie
- a.com 接收请求后,对请求进行验证,此时已经确认是受害者发起的请求
a.com 以受害者的名义执行了xxx=123
当然解决这个安全问题,业界已经为我们总结了很多方案,比如 同源检测,Origin Header等等。不过,大体上前端的安全性我们能注重一些常见问题,基本上能涵盖80%以上的问题。
对于安全问题,业界大佬推荐使用 https://msdn.microsoft.com/zh-cn/magazine/dd347831.aspx?f=255&MSPPError=-2147217396 来创建威胁模型,被归纳为STRIDE 威胁建模,它分为如下六个纬度:
- Spoofing
- Tampering
- Repudiation
- Information Disclosure
- Denial of Service
- Elevation of Privilege
大体上这六个纬度就已经涵盖了几乎所有的安全性问题。那么对于前端的项目,我们可以从这六个纬度中去评估自己的项目而得到答案。
隐私和广而告之
谈及隐私是因为如今越演越烈的隐私泄露,大数据等技术的成熟度将一个人的画像描绘的越来越清晰,数据几乎就是“钱”的代名词。
可是对于前端而言(Web世界里),隐私的泄露和 `Cookie` `localStorage` 息息相关。如今的 Web 世界里被追踪的脚本大多数是用 Cookie 来实现的,简单的来说多数网站的登录持久化基本上都依赖于存储在你设备上的 Cookie,而对于广告平台的第三方 Cookie 除了隐私问题外,很有可能还有 `安全性` 的问题,如果这个脚本被劫持了的话,但大多数浏览器都默认提供了屏蔽第三方 Cookie,后来大家想到的是通过 `localStorage` 的方案去绕过被屏蔽的第三方 Cookie,这种越演越烈的广告脚本追踪,几乎就是你浏览网页在 Web 的世界里被泄露隐私的来源之一。
有时候真的很想要一个不被追踪而又能搜索数据的搜索引擎,但久久不可询,`隐私` 真是一个可爱可恨的事情,除非有人能去做这样的事情。正好 https://mijisou.com 秘迹搜是一个真正可以保护你个人隐私的网络搜索服务,它不会记录任何你的查询关键字,也从不存储你的个人信息,不传播你的任何信息,真正做到搜索不留痕,摆脱你不想要的定向广告的骚扰和可能的隐私泄露,它完美的符合了我的预期。