http协议是使用明文传输的,如果在传输链路上被拦截,会造成信息泄露,这就是中间人攻击
;
通信双方拥有同一个密钥,可以通过这个密钥进行加密解密(MD5就是使用的对称加密);
为什么对称加密不适合? 服务器如何安全的把密钥发送给客户端?没有办法!除非浏览器预存了所有https网站服务的密钥,这个不现实,所以需要非对称加密
一个公钥,一个私钥,公钥加密的数据需要用私钥解密,私钥加密的数据需要用公钥解密; 如何使用非对称加密实现安全连接? 1.客户端拥有公钥X,私钥X^, 服务端拥有公钥Y,私钥Y^。 2.客户端把公钥X发送给服务端,服务端使用公钥X加密数据后发送给客户端,客户端拥有X^私钥解密服务端返回的数据。 3.服务端吧公钥Y发送给客户端,客户端使用公钥Y加密数据后发送给服务端,服务端拥有Y^私钥解密客户端发送的数据。 4.因为私钥是安全且不被明文传输,所以这种方式是较为安全的。 5.由于非对称加密比较耗费性能,而对称加密要快的多。 6.不过这种方式还是有漏洞,中间人攻击还是可以欺骗客户端及服务端。
可以使用 非对称加密 来 加密 对称加密中的 密钥。保证密钥不被第三方知晓,然后使用对称加密来传输数据。 1.服务端拥有公钥Y,私钥Y^. 2.服务端将公钥Y明文发送给客户端。 3.客户端随机生成一个用与对称加密的密钥X,使用公钥Y加密后发送给服务端。 4.服务端使用私钥Y^解密后得到密钥X,这样双方都拥有了密钥X,且密钥X不被外部知晓。 5.这种方式节省性能,非对称加密解密均只是执行了一次,但是还是有漏洞,中间人攻击还是可以欺骗客户端及服务端。
中间人攻击是指在数据传输链路上被劫持,数据被修改,且通信双方不知道数据被修改了 1.服务端拥有公钥Y,私钥Y^. 2.服务端将公钥Y明文发送给客户端。 3.中间人劫持到公钥Y,保存下来,且中间人拥有自己的公钥B,私钥B^,中间人将公钥B发送给客户端。 4.客户端使用公钥B加密随机生成的对称加密的密钥X,发送给服务器(浏览器无法得知公钥被替换了)。 5.中间人劫持后,使用私钥B^解密出来密钥X,然后用服务端的公钥Y加密后发送到服务器。 6.这样中间人就代理成了客户端了,能破解所有传输的数据了。
浏览器如何校验接收到的公钥是正确网站的公钥? CA机构就是发放安全域名的中央,是值得信赖的,由它给网站发放唯一的”身份证“,这个”身份证“就是数字证书。 使用数字证书来保证明文传输的公钥是没有被污染的 1.数字证书拥有持有者的信息以及公钥。 2.客户端向CA机构获取该网站服务的数字证书,包含了持有者的信息及公钥,校验是否正确。 3.如果校验通过,则使用公钥加密随机生成的密钥X,发送到服务端,进行对称加密数据传输。
为什么数字证书能保证公钥是没有被污染的? 数字签名的制作过程: 1.CA机构拥有公钥及私钥 2.CA机构对数字证书明文数据T进行hash 3.CA机构对hash后的值用私钥加密,得到数字签名S 明文和数字签名组成了数字证书,这样一份数字证书就可以颁发给网站了
浏览器的验证过程: 1.浏览器拿到证书,得到明文T,以及数字签名S 2.拿到公钥,对数字签名S进行解密,得到明文T进行hash后的数据S^ 3.拿到明文中的hash算法,对明文T进行hash,得到T^ 4.即 S^ === T^ 则验证通过
1.函数是值,它可以在代码任何地方被分配,赋值或声明 2.如果函数被声明为单独的语句,则是一个函数声明 3.如果函数是作为表达式的一部分创建的,则是一个函数表达式 4.函数声明会在引擎初始化代码时被寻找且创建这些函数
console.log(a) // ƒ a() { console.log('caonima')}
function a() {
console.log('caonima')
}
5.函数表达式在执行流程到达时创建
垃圾回收是自动完成的,我们不能强制执行或是阻止执行。 当对象是可达状态时,它一定是存在于内存中的。 被引用与可访问(从一个根)不同:一组相互连接的对象可能整体都不可达。
对象通过引用被赋值和拷贝。换句话说,一个变量存储的不是“对象的值”,而是一个对值的“引用”(内存地址)。因此,拷贝此类变量或将其作为函数参数传递时,所拷贝的是引用,而不是对象本身。
所有通过被拷贝的引用的操作(如添加、删除属性)都作用在同一个对象上。
为了创建“真正的拷贝”(一个克隆),我们可以使用 Object.assign 来做所谓的“浅拷贝”(嵌套对象被通过引用进行拷贝)或者使用“深拷贝”函数,例如 _.cloneDeep(obj)。
this 的值是在程序运行时得到的。
我们可以使用构造函数来创建多个类似的对象。 JavaScript 为许多内建的对象提供了构造函数:比如日期 Date、集合 Set
Symbol
是唯一标识符的基本类型
Symbol总是不同的值,即便它们有相同的名字,如果我们希望同名的 symbol 相等,那么我们应该使用全局注册表:Symbol.for(key) 返回(如果需要的话则创建)一个以 key 作为名字的全局 symbol。使用 Symbol.for 多次调用 key 相同的 symbol 时,返回的就是同一个 symbol。
symbol 有两个主要的使用场景: 1.“隐藏”对象属性 如果我们使用了其他脚本的一个对象user,我们希望给这个对象添加属性,可以创建一个 symbol 用于该对象属性的键,symbol 属性不会出现在 for..in 中,因此它不会意外地被与其他属性一起处理。并且,它不会被直接访问,因为另一个脚本没有我们的 symbol。因此,该属性将受到保护,防止被意外使用或重写。
因此我们可以使用 symbol 属性“秘密地”将一些东西隐藏到我们需要的对象中,但其他地方看不到它。
2.JavaScript 使用了许多系统 symbol,这些 symbol 可以作为 Symbol.* 访问。我们可以使用它们来改变一些内建行为。例如,我们将使用 Symbol.iterator 来进行 迭代 操作,使用 Symbol.toPrimitive 来设置 对象原始值的转换 等等。
let range = {
from: 1,
to: 5
};
// 1. for..of 调用首先会调用这个:
range[Symbol.iterator] = function() {
// ……它返回迭代器对象(iterator object):
// 2. 接下来,for..of 仅与下面的迭代器对象一起工作,要求它提供下一个值
return {
current: this.from,
last: this.to,
// 3. next() 在 for..of 的每一轮循环迭代中被调用
next() {
// 4. 它将会返回 {done:.., value :...} 格式的对象
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// 现在它可以运行了!
for (let num of range) {
alert(num); // 1, 然后是 2, 3, 4, 5
}
词法环境
hint: