一、URL简介
1、网址的组成部分
URL 由多个部分组成。下面是一个比较复杂的 URL,实际的 URL 通常不会有这么多部分。
https://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#anchor
http+tls
加密流程
dns工作原理
A NS MX
ftp://20 21
1-65535
1-1023
25 smtp 邮件
53
67 68 dhcp dhcp 1 discover br 2 offer 3 request 4 ack 5 arp 3次 免费arp
ip地址冲突
arp分类
80
110 pop3
135 139
445 共享协议 ms17-010 永恒之蓝 win7
arp欺骗
389 ldap 域控制器 Active director ldap 注入
3306 mysql 关系型
6379 redis 非关系型 select 70% update insert delete 30%
我们看看,这个 URL 的各个部分。
2、协议
协议(scheme)是浏览器请求服务器资源的方法,上例是https://
的部分,表示使用 HTTPS 协议。
互联网支持多种协议,必须指明网址使用哪一种协议,默认是 HTTP 协议。也就是说,如果省略协议,直接在浏览器地址栏输入www.example.com
,那么浏览器默认会访问http://www.example.com
。HTTPS 是 HTTP 的加密版本,出于安全考虑,越来越多的网站使用这个协议。
HTTP 和 HTTPS 的协议名称后面,紧跟着一个冒号和两个斜杠(://
)。其他协议不一定如此,邮件地址协议mailto:
的协议名后面只有一个冒号,比如mailto:foo@example.com
。
3、主机
主机(host)是资源所在的网站名或服务器的名字,又称为域名。上例的主机是www.example.com
。
有些主机没有域名,只有 IP 地址,比如192.168.2.15
。这种情况常常出现在局域网。
dns www.xianoupeng.com 缓存有 直接返回 缓存没有 hosts 没有 找网关内置dns 内置根域 tcp/ip 三次握手
request
response
301 302 303 304 307 308
301、308:永久重定向
302、307:临时重定向
301:资源已经永久的转移,允许将post改成get
302:资源临时转移,允许将post改成get
303:将post请求重定向到get请求
304:GET请求已被允许,而文档的内容并没有改变
307:资源临时转移,不允许将post改成get
308:资源永久转移,不允许将post改成get
4、端口
同一个域名下面可能同时包含多个网站,它们之间通过端口(port)区分。“端口”就是一个整数,可以简单理解成,访问者告诉服务器,想要访问哪一个网站。HTTP 协议的默认端口是80,如果省略了这个参数,服务器就会返回80端口的网站。
端口紧跟在域名后面,两者之间使用冒号分隔,比如www.example.com:80
。
二、URL 字符
URL 的各个组成部分,只能使用以下这些字符。
-
26个英语字母(包括大写和小写)
-
10个阿拉伯数字
-
连词号(
-
) -
句点(
.
) -
下划线(
_
)绕过
此外,还有18个字符属于 URL 的保留字符,只能在给定的位置出现。比如,查询参数的开头是问号(?
),也就是说,问号只能出现查询参数的开头,出现在其他位置就是非法的,会导致网址解析错误。网址的其他部分如果要使用这些保留字符,必须使用它们的转义形式。
URL 字符转义的方法是,在这些字符的十六进制 ASCII 码前面加上百分号(%
)。下面是这18个字符及其转义形式。
!
:%21#
:%23$
:%24&
:%26'
:%27(
:%28)
:%29*
:%2A+
:%2B,
:%2C/
:%2F:
:%3A;
:%3B=
:%3D?
:%3F@
:%40[
:%5B]
:%5D
举例来说,有一个网页的 URL 是foo?bar.html
,即文件里面包含一个问号,那么需要写成foo%3Fbar.html
。
URL 的合法字符,其实也可以采用这种转义方法,但是不建议使用。比如,字母a
的十六进制 ASCII 码是61
,转义形式后就是%61
。因此,www.apple.com
又可以写成www.%61pple.com
,浏览器一样识别。
值得注意的是,空格的转义形式是%20
。对于那些包含空格的文件名,这个转义是必须的。
既不属于合法字符、也不属于保留字符的其他字符(比如汉字),理论上不需要手动转义,可以直接写在 URL 里面,比如www.example.com/中国.html
,浏览器会自动将它们转义,发给服务器。转义方法是使用这些字符的十六进制 UTF-8 编码,每两位算作一组,然后每组头部添加百分号(%
)。
举例来说,汉字中
的 UTF-8 十六进制编码是e4b8ad
,每两个字符一组,URL 转义后就为%e4%b8%ad
。也就是说,URL 里面凡是有汉字中
的地方,都要写成%e4%b8%ad
。因此,访问www.example.com/中国.html
这个网址,需要写成下面的样子。
www.example.com/%e4%b8%ad%e5%9b%bd.html
上面代码中,中
的转义形式是%e4%b8%ad
,国
是%e5%9b%bd
。
三、DNS的记录类型
域名与IP之间的对应关系,称为"记录"(record)。根据使用场景,"记录"可以分成不同的类型(type),前面已经看到了有A
记录和NS
记录。www.baidu.com 1.1.1.1
常见的DNS记录类型如下。
(1)
A
:地址记录(Address),返回域名指向的IP地址。(2)
NS
:域名服务器记录(Name Server),返回保存下一级域名信息的服务器地址。该记录只能设置为域名,不能设置为IP地址。(3)
MX
:邮件记录(Mail eXchange),返回接收电子邮件的服务器地址。(4)
CNAME
:规范名称记录(Canonical Name),返回另一个域名,即当前查询的域名是另一个域名的跳转,详见下文。(5)
PTR
:逆向查询记录(Pointer Record),只用于从IP地址查询域名,详见下文。
一般来说,为了服务的安全可靠,至少应该有两条NS
记录,而A
记录和MX
记录也可以有多条,这样就提供了服务的冗余性,防止出现单点失败。
CNAME
记录主要用于域名的内部跳转,为服务器配置提供灵活性,用户感知不到。举例来说,facebook.github.io
这个域名就是一个CNAME
记录。
$ dig facebook.github.io ... ;; ANSWER SECTION: facebook.github.io. 3370 IN CNAME github.map.fastly.net. github.map.fastly.net. 600 IN A 103.245.222.133
上面结果显示,facebook.github.io
的CNAME记录指向github.map.fastly.net
。也就是说,用户查询facebook.github.io
的时候,实际上返回的是github.map.fastly.net
的IP地址。这样的好处是,变更服务器IP地址的时候,只要修改github.map.fastly.net
这个域名就可以了,用户的facebook.github.io
域名不用修改。
由于CNAME
记录就是一个替换,所以域名一旦设置CNAME
记录以后,就不能再设置其他记录了(比如A
记录和MX
记录),这是为了防止产生冲突。举例来说,foo.com
指向bar.com
,而两个域名各有自己的MX
记录,如果两者不一致,就会产生问题。由于顶级域名通常要设置MX
记录,所以一般不允许用户对顶级域名设置CNAME
记录。
PTR
记录用于从IP地址反查域名。dig
命令的-x
参数用于查询PTR
记录。
$ dig -x 192.30.252.153 ... ;; ANSWER SECTION: 153.252.30.192.in-addr.arpa. 3600 IN PTR pages.github.com.
上面结果显示,192.30.252.153
这台服务器的域名是pages.github.com
。
逆向查询的一个应用,是可以防止垃圾邮件,即验证发送邮件的IP地址,是否真的有它所声称的域名。
dig
命令可以查看指定的记录类型。
$ dig a github.com $ dig ns github.com $ dig mx github.com
四、id
id
属性是元素在网页内的唯一标识符。比如,网页可能包含多个<p>
标签,id
属性可以指定每个<p>
标签的唯一标识符。
<p id="p1"></p>
<p id="p2"></p>
<p id="p3"></p>
上面代码中,三个<p>
标签具有不同的id
属性,因此可以区分。
id
属性的值必须是全局唯一的,同一个页面不能有两个相同的id
属性。另外,id
属性的值不得包含空格。
id
属性的值还可以在最前面加上#
,放到 URL 中作为锚点,定位到该元素在网页内部的位置。比如,用户访问网址https://foo.com/index.html#bar
的时候,浏览器会自动将页面滚动到bar
的位置,让用户第一眼就看到这部分内容。
五、RSA密钥协商握手过程
单钥匙就是对称加密,对称加密的速度很快,可以用于传输过程中的数据加密,防止中间人查看和篡改信息。
双钥匙就是非对称加密,非对称加密的速度慢,可以用于加密少量数据,同时也可以用于签名防止篡改。
公钥加密,私钥解密,这个叫加密,是为了保证内容安全,因为私钥只有自己知道,是为了保证这个信息不被中间人解开。
私钥加密,公钥解密,这个叫签名,是为了防止内容被篡改,因为公钥所有人都知道,所有人都能看到这个信息做验证。
六、数字证书和 CA 机构
在说校验数字证书是否可信的过程前,我们先来看看数字证书是什么,一个数字证书通常包含了:
- 公钥;
- 持有者信息;
- 证书认证机构(CA)的信息;
- CA 对这份文件的数字签名及使用的算法;
- 证书有效期;
- 还有一些其他额外信息;
那数字证书的作用,是用来认证公钥持有者的身份,以防止第三方进行冒充。说简单些,证书就是用来告诉客户端,该服务端是否是合法的,因为只有证书合法,才代表服务端身份是可信的。
我们用证书来认证公钥持有者的身份(服务端的身份),那证书又是怎么来的?又该怎么认证证书呢?
为了让服务端的公钥被大家信任,服务端的证书都是由 CA (Certificate Authority,证书认证机构)签名的,CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的。
之所以要签名,是因为签名的作用可以避免中间人在获取证书时对证书内容的篡改。
七、数字证书签发和验证流程
如下图图所示,为数字证书签发和验证流程:
CA 签发证书的过程,如上图左边部分:
- 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
- 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2 ;
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
八、RSA 算法的缺陷
使用 RSA 密钥协商算法的最大问题是不支持前向保密。因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。
为了解决这一问题,于是就有了 DH 密钥协商算法,这里简单介绍它的工作流程。
客户端和服务端各自会生成随机数,并以此作为私钥,然后根据公开的 DH 计算公示算出各自的公钥,通过 TLS 握手双方交换各自的公钥,这样双方都有自己的私钥和对方的公钥,然后双方根据各自持有的材料算出一个随机数,这个随机数的值双方都是一样的,这就可以作为后续对称加密时使用的密钥。
DH 密钥交换过程中,即使第三方截获了 TLS 握手阶段传递的公钥,在不知道的私钥的情况下,也是无法计算出密钥的,而且每一次对称加密密钥都是实时生成的,实现前向保密。
但因为 DH 算法的计算效率问题,后面出现了 ECDHE 密钥协商算法,我们现在大多数网站使用的正是 ECDHE 密钥协商算法。
九、字符的数字表示法
网页可以使用不同语言的编码方式,但是最常用的编码是 UTF-8。UTF-8 编码是 Unicode 字符集的一种表达方式。这个字符集的设计目标是包含世界上的所有字符,目前已经收入了十多万个字符。
每个字符有一个 Unicode 号码,称为码点(code point)。如果知道码点,就能查到这是什么字符。举例来说,英文字母a
的码点是十进制的97
(十六进制的61
),汉字“中”的码点是十进制的20013
(十六进制的4e2d
)。
由于下面的原因,不是每一个 Unicode 字符都能直接在 HTML 语言里面显示。
(1)不是每个 Unicode 字符都可以打印出来,有些没有可打印形式,比如换行符的码点是十进制的10
(十六进制的A
),就没有对应的字面形式。
(2)小于号(<
)和大于号(>
)用来定义 HTML 标签,其他需要用到这两个符号的场合,必须防止它们被解释成标签。
(3)由于 Unicode 字符太多,无法找到一种输入法,可以直接输入所有这些字符。换言之,没有一种键盘,有办法输入所有符号。
(4)网页不允许混合使用多种编码,如果使用 UTF-8 编码的同时,又想插入其他编码的字符,就会很困难。
HTML 为了解决上面这些问题,允许使用 Unicode 码点表示字符,浏览器会自动将码点转成对应的字符。
字符的码点表示法是&#N;
(十进制,N
代表码点)或者&#xN;
(十六进制,N
代表码点),比如,字符a
可以写成a
(十进制)或者a
(十六进制),字符中
可以写成中
(十进制)或者中
(十六进制),浏览器会自动转换它们。
<p>hello</p>
<!-- 等同于 -->
十进制
<p>hello</p>
<!-- 等同于 -->
十六进制
<p>hello</p>
上面代码中,字符可以直接表示,也可以使用十进制码点或十六进制码点表示。
注意,HTML 标签本身不能使用码点表示,否则浏览器会认为这是所要显示的文本内容,而不是标签。比如,<p>
一旦写成<p>
或者<p>
,浏览器就不再认为这是标签了,而会当作文本内容将其显示为<p>
。
十、字符的实体表示法
数字表示法的不方便之处,在于必须知道每个字符的码点,很难记忆。为了能够快速输入,HTML 为一些特殊字符,规定了容易记忆的名字,允许通过名字来表示它们,这称为实体表示法(entity)。
实体的写法是&name;
,其中的name
是字符的名字。下面是其中一些特殊字符,及其对应的实体。
<
:<
>
:>
"
:"
'
:'
&
:&
©
:©
#
:#
§
:§
¥
:¥
$
:$
£
:£
¢
:¢
%
:%
*
:$ast;
@
:@
^
:^
±
:±
- 空格:
注意,上面最后一个特殊字符是空格,它也有对应的实体表示法。
字符的数字表示法和实体表示法,都可以表示正常情况无法输入的字符,逃脱了浏览器的限制,所以英语里面称为“escape”,中文翻译为“字符的转义”。
十一、<a>
标签
链接通过<a>
标签表示,用户点击后,浏览器会跳转到指定的网址。下面就是一个典型的链接。
<a href="https://wikipedia.org/">维基百科</a>
上面代码就定义了一个超级链接。浏览器显示“维基百科”,文字下面默认会有下划线,表示这是一个链接。用户点击后,浏览器跳转到href
属性指定的网址。
<a>
标签内部不仅可以放置文字,也可以放置其他元素,比如段落、图像、多媒体等等。
<a href="https://www.example.com/">
<img src="https://www.example.com/foo.jpg">
</a>
上面代码中,<a>
标签内部就是一个图像。用户点击图像,就会跳转到指定网址。
<a>
标签有如下属性。
(1)href
href
属性给出链接指向的网址。它的值应该是一个 URL 或者锚点。
上文已经给出了完整 URL 的例子,下面是锚点的例子。
<a href="#demo">示例</a>
上面代码中,href
属性的值是#
加上锚点名称。点击后,浏览器会自动滚动,停在当前页面里面demo
锚点所在的位置。
(2)hreflang
hreflang
属性给出链接指向的网址所使用的语言,纯粹是提示性的,没有实际功能。
<a
href="https://www.example.com"
hreflang="en"
>示例网址</a>
上面代码表明,href
属性指向的网址的语言是英语。
该属性的值跟通用属性lang
一样,语言代码可以参考《属性》一章的lang
属性的介绍。
(3)title
title
属性给出链接的说明信息。鼠标悬停在链接上方时,浏览器会将这个属性的值,以提示块的形式显示出来。
<a
href="https://www.example.com/"
title="hello"
>示例</a>。
上面代码中,用户鼠标停留在链接上面,会出现文字提示hello
。
(4)target
target
属性指定如何展示打开的链接。它可以是在指定的窗口打开,也可以在<iframe>
里面打开。
<p><a href="http://foo.com" target="test">foo</a></p>
<p><a href="http://bar.com" target="test">bar</a></p>
上面代码中,两个链接都在名叫test
的窗口打开。首先点击链接foo
,浏览器发现没有叫做test
的窗口,就新建一个窗口,起名为test
,在该窗口打开foo.com
。然后,用户又点击链接bar
,由于已经存在test
窗口,浏览器就在该窗口打开bar.com
,取代里面已经打开的foo.com
。
target
属性的值也可以是以下四个关键字之一。
_self
:当前窗口打开,这是默认值。_blank
:新窗口打开。_parent
:上层窗口打开,这通常用于从父窗口打开的子窗口,或者<iframe>
里面的链接。如果当前窗口没有上层窗口,这个值等同于_self
。_top
:顶层窗口打开。如果当前窗口就是顶层窗口,这个值等同于_self
。
<a
href="https://www.example.com"
target="_blank"
>示例链接</a>
上面代码点击后,浏览器会新建一个窗口,在该窗口打开链接,并且新窗口没有名字。
注意,使用target
属性的时候,最好跟rel="noreferrer"
一起使用,这样可以避免安全风险。
(5)rel
rel
属性说明链接与当前页面的关系。
<a href="help.html" rel="help">帮助</a>
上面代码的rel
属性,说明链接是当前页面的帮助文档。
下面是一些常见的rel
属性的值。
alternate
:当前文档的另一种形式,比如翻译。author
:作者链接。bookmark
:用作书签的永久地址。external
:当前文档的外部参考文档。help
:帮助链接。license
:许可证链接。next
:系列文档的下一篇。nofollow
:告诉搜索引擎忽略该链接,主要用于用户提交的内容,防止有人企图通过添加链接,提高该链接的搜索排名。noreferrer
:告诉浏览器打开链接时,不要将当前网址作为 HTTP 头信息的Referer
字段发送出去,这样可以隐藏点击的来源。noopener
:告诉浏览器打开链接时,不让链接窗口通过 JavaScript 的window.opener
属性引用原始窗口,这样就提高了安全性。prev
:系列文档的上一篇。search
:文档的搜索链接。tag
:文档的标签链接。
(6)referrerpolicy
一定程度的限制csrf
referere
referrerpolicy
属性用于精确设定点击链接时,浏览器发送 HTTP 头信息的Referer
字段的行为。
该属性可以取下面八个值:no-referrer
、no-referrer-when-downgrade
、origin
、origin-when-cross-origin
、unsafe-url
、same-origin
、strict-origin
、strict-origin-when-cross-origin
。
其中,no-referrer
表示不发送Referer
字段,same-origin
表示同源时才发送Referer
字段,origin
表示只发送源信息(协议+域名+端口)。其他几项的解释,请查阅 HTTP 文档。
(7)ping
ping
属性指定一个网址,用户点击的时候,会向该网址发出一个 POST 请求,通常用于跟踪用户的行为。
(8)type
type
属性给出链接 URL 的 MIME 类型,比如到底是网页,还是图像或文件。它也是纯粹提示性的属性,没有实际功能。
<a
href="smile.jpg"
type="image/jpeg"
>示例图片</a>
上面代码中,type
属性提示这是一张图片。
(9)download
download
属性表明当前链接用于下载,而不是跳转到另一个 URL。
<a href="demo.txt" download>下载</a>
上面代码点击后,会出现下载对话框。
注意,download
属性只在链接与网址同源时,才会生效。也就是说,链接应该与网址属于同一个网站。
如果download
属性设置了值,那么这个值就是下载的文件名。
<a
href="foo.exe"
download="bar.exe"
>点击下载</a>
上面代码中,下载文件的原始文件名是foo.exe
。点击后,下载对话框提示的文件名是bar.exe
。
注意,如果链接点击后,服务器的 HTTP 回应的头信息设置了Content-Disposition
字段,并且该字段的值与download
属性不一致,那么该字段优先,下载时将显示其设置的文件名。
download
属性还有一个用途,就是有些地址不是真实网址,而是数据网址,比如data:
开头的网址。这时,download
属性可以为虚拟网址指定下载的文件名。
<a href="data:,Hello%2C%20World!">点击</a>
上面链接点击后,会打开一个虚拟网页,上面显示Hello World!
。
<a
href="data:,Hello%2C%20World!"
download="hello.txt"
>点击</a>
上面链接点击后,下载的hello.txt
文件内容就是“Hello, World!”。
十二、<link>
标签
基本用法
<link>
标签主要用于将当前网页与相关的外部资源联系起来,通常放在<head>
元素里面。最常见的用途就是加载 CSS 样式表。
<link rel="stylesheet" type="text/css" href="theme.css">
上面代码为网页加载样式表theme.css
。
除了默认样式表,网页还可以加载替代样式表,即默认不生效、需要用户手动切换的样式表。
<link href="default.css" rel="stylesheet" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" title="Basic">
上面代码中,default.css
是默认样式表,默认就会生效。fancy.css
和basic.css
是替换样式表(rel="alternate stylesheet"
),默认不生效。title
属性在这里是必需的,用来在浏览器菜单里面列出这些样式表的名字,供用户选择,以替代默认样式表。
<link>
还可以加载网站的 favicon 图标文件。
<link rel="icon" href="/favicon.ico" type="image/x-icon">
手机访问时,网站通常需要提供不同分辨率的图标文件。
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="favicon114.png">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="favicon72.png">
上面代码指定 iPhone 设备需要的114像素和72像素的图标。
<link>
也用于提供文档的相关链接,比如下面是给出文档的 RSS Feed 地址。
<link rel="alternate" type="application/atom+xml" href="/blog/news/atom">