跳到主要内容

前端面试-计算机网络

针对 Web 的攻击技术 XSS 与 CSRF

HTTP 协议内并不具备 会话(session)管理加密处理等安全性方面的功能。在 Web 应用中,从浏览器那接收到的 HTTP 请求的全部内容,都可以在客户端自由的变更、篡改。所以 Web 应用可能会接收到与预期数据不相同的内容。

在 HTTP 请求报文内加载攻击代码,就能发起对 Web 应用的攻击。通过 URL 查询字段或表单、HTTP 首部、Cookie 等途径把攻击代码传入,若这时 Web 应用存在安全泄漏,那内部信息就会遭到窃取,或者被攻击者拿到管理权限

对 Web 应用对攻击模式有两种 :

  • 主动攻击
  • 被动攻击

以服务器为目标的主动攻击

主动攻击是指攻击者通过直接访问 Web 应用,把攻击代码传入的攻击模式。由于该模式是直接针对服务器上对的资源进行攻击,因此攻击者需要能够访问到那些资源,主动攻击模式里,最具有代表性的是 : SQL注入攻击OS命令注入攻击

以服务器为目标的被动攻击

被动攻击是指利用圈套策略执行攻击代码的攻击模式,通常都是诱导用户触发已设置好的陷阱,而陷阱会启动发送已嵌入攻击代码的 HTTP 请求。中招后的用户浏览器会把含有攻击代码的 HTTP 请求发送给作为攻击目标的 Web 应用,运行攻击代码。执行完攻击代码之后,可能会导致用户所持有的 Cookie 等个人信息被窃取,登陆状态中的用户权限遭到恶意滥用等后果

被动攻击模式最具有代表性的是 : 跨站脚本攻击(XSS)跨站请求伪造(CSRF)

利用用户身份攻击企业内部网络

利用被动攻击,可发起对原本从互联网上无法直接访问的企业内部等网络的攻击。只要用户踏入攻击者预先设定好的陷阱,在用户能够访问到的网络范围内,即使是企业内网也同样会受到攻击。


使用 XSS 攻击

xss 叫做跨站脚本攻击,是一种 web 应用中的计算机漏洞,当用户浏览器渲染整个 HTML 文档的过程中出现了不被预期的脚本指令并执行时,XSS 就会发生。(这个逼装的好,鼓个掌)

它指的是恶意攻击者往 Web 页面里插入恶意 html 代码,当用户浏览该页之时,嵌入其中 Web 里面的 html 代码会被执行,从而达到恶意攻击用户的特殊目的。

XSS 分为三种

反射型XSS : 这种xss,跨站代码一般存在于某一个链接中,当被攻击者访问这样的连接时,跨站代码就被执行,这类跨站代码一般不会存储在服务器上面
存储型XSS : 这种xss用起来比较方便,跨站代码会存储在服务器上面数据库中,换句话就是可以持久的进行攻击,亦称持久型XSS
基于DOM的XSS : 这是由于客户端脚本自身的解析不正确导致的安全问题

如何攻击 ?

XSS 通过修改 HTML 节点或者执行 JS 代码来攻击网站。

<!-- 比如在一个留言板中插入xss代码,前提是留言内容不过滤 -->

<!-- 在文本框中添加 -->
<script>
alert("我是XSS攻击");
</script>

<!-- 这时候点击留言,脚本被执行,就会弹出对话框,这就说明存在XSS危害 -->

如何预防 ?

最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义

function escape(str) {
str = str.replace(/&/g, "&amp;");
str = str.replace(/</g, "&lt;");
str = str.replace(/>/g, "&gt;");
str = str.replace(/"/g, "&quto;");
str = str.replace(/'/g, "&##39;");
str = str.replace(/`/g, "&##96;");
str = str.replace(/\//g, "&##x2F;");
return str;
}

// 通过转义,将攻击代码变成
escape("<script>alert(1)</script>");
// &lt;script&gt;alert(1)&lt;&##x2F;script&gt;

CSRF 跨站请求伪造

你可以这样理解 : 攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。

我们是实在人,举个实在例子

受害者 A 在银行有一笔存款,通过对银行的网站发送请求 http://bank.example/withdraw?account=A&amount=1000000&for=B 可以使 A 把 1000000 的存款转到 B 的账号下。

通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。

黑客 B 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=A&amount=1000000&for=B。 但是这个请求来自 B 而非 A,他不能通过安全认证,因此该请求不会起作用。

这时,B 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=A&amount=1000000&for=B”,并且通过广告等诱使 A 来访问他的网站。

当 A 访问该网站时,上述 url 就会从 A 的浏览器发向银行,而这个请求会附带 A 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 A 的认证信息。

但是!!!如果 A 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 A 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 A 的账号转移到 B 的账号,而 A 当时毫不知情。

等以后 A 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 B 则可以拿到钱后逍遥法外。

如何防御

    1 、 验证 HTTP Referer 字段;Referer 来判断该请求是否为第三方网站发起的

2 、 在请求地址中添加 token 并验证;由服务器下发一个随机 Token(算法不能复杂),每次发起请求时将 Token 携带上,服务器验证 Token 是否有效。

3 、 在 HTTP 头中自定义属性并验证。可以对 Cookie 设置 SameSite 属性。该属性设置 Cookie 不随着跨域请求发送,该属性可以很大程度减少 CSRF 的攻击

SQL 注入攻击

SQl 注入攻击是指针对 Web 应用使用的数据库,通过运行非法的 SQL 语句而产生的攻击。正常情况下:从 book 表中搜索作者 author = 'PDK' 且 flag = 1 的符合数据

  URL: http://www.pengdaokuan.cn/search?q=PDK

然后在 SQL 语句为:

  SELECT * FROM book WHERE author = 'PDK' and flag = 1;

但是如果通过把查询字段改为: PDK -> PDK-- 那么构成的 SQl 语句就变成了这样

  SELECT * FROM book WHERE author = 'PDK' --' and flag = 1;

SQL 语句中的--之后全视为注释,即,and flag = 1 这个条件被自动忽略了!


HTTP 首部注入攻击

HTTP 首部注入攻击是值攻击者通过在响应首部字段内插入换行,添加任意响应首部或者主体的一种攻击。输入被动攻击模式

向首部主体内添加内容的攻击称为 HTTP 响应截断攻击,Web 应用有时会把外部接收到的数值,赋给响应首部字段 LocationSet-Cookie

  Location: http://www.pengdaokuan.cn/a.php?q=pdk
Set-Cookie: UID=pdk

*pdk就是插入值

HTTP 首部注入攻击有可能会造成以下一些影响

  • 设置任何 Cookie 信息

  • 重定向至任意 URL

  • 显示任意的主体(HTTP 响应截断攻击)


开放重定向

开放重定向是一种对指定的任意 URL 作重定向跳转的功能。而于此功能相关联的安全漏洞是指: 加入指定的重定向 URL 到某个恶意的 Web 网站,那么用户就会被诱导至那个 Web 网站。


会话劫持

是指通过某种手段拿到用户的会话 ID,并没法使用此会话 ID 伪装成用户,达到攻击的目的。

具备认证功能的 Web 应用,使用会话 ID 的会话管理机制,作为管理认证状态的主流方式。会话 ID 中记录客户端的 Cookie 等信息,服务器端将会话 ID 与认证状态进行一对一匹配管理

下面列举几种攻击者可获得会话 ID 的途径

  • 通过非正规的生成方法推测会话 ID

  • 通过窃听或 XSS 攻击盗取会话 ID

  • 通过会话固定攻击强行获取会话 ID


其他安全漏洞

密码破解

密码破解攻击即算出密码,突破认证。密码破解有以下两种手段:

  • 通过网络的密码试错 (两种方式: 穷举法和字典攻击)

穷举法,又称为暴力破解法,是对所有密钥集合构成的密钥空间进行穷举,用所有可行的候选密码对目标的密码系统试错,用以突破验证的一种攻击。比如银行采用“4 位数字”组成的密码,那么就要从 0000 ~ 9999 中的全部数字进行逐个尝试。这样必定能在候选的密码集合中找到正确的密码,可通过认证,但时间太久,这种攻击是失败的。 字典攻击,利用实现收集好的候选密码(通过各种组合方式后存入字典),枚举字典中的密码。尝试通过认证的一种攻击手段。比如银行采用“4 位数字”组成的密码,考虑到用户可能会用自己的生日做密码,于是可以将 0101 ~ 1231 保存成字典,进行尝试。此方法攻击耗时相对穷举比较短,但是攻击的成败取决于字典的内容。如果字典中没有正确的密码,那么就无法破解成功

  • 对已加密密码的破解

web 应用在保存密码时,一般不会明文方式保存,而是通过散列函数做散列处理或者通过 xml64,md5 等加密方式,所以想要取得真实密码,需要通过解码手段。把密码还原成明文形式。

点击劫持

点击劫持是值利用透明的按钮或链接做成陷阱,覆盖在 web 页面上,然后诱导用户在不知情的情况下,点击那个链接访问内容的一种攻击手段。这种行为又称为界面伪装(UI Redressing)

从输入 URL 到页面加载完成的过程

让我们思考一个问题,你在浏览器中输入: www.baidu.com 的时候,在你按下回车的那一瞬间,发生了什么事情,为什么能够在你按下之后,就能将百度的首页返回?

“WC,很简单啊,就是发送一个请求然后就获取了呗~” emmmm,很简洁的答案。那么具体是为什么呢?直到我看了阮一峰的互联网协议入门(一)之后,才明白原因。耐心的小伙伴可以去看一看阮一峰的教程。如果是想简单知道,那么就继续往下看哈~

所谓的网络通信就是交换数据包。电脑 A 向电脑 B 发送一个数据包,后者收到了,回复一个数据包,从而实现两台电脑之间的通信。那么发送这个包,需要知道两个地址:

  • 对方的 MAC 地址

  • 对方的 IP 地址

有了这两个地址,数据包才能准确送到接收者手中。但是,MAC 地址有局限性,如果两台电脑不在同一个子网络,就无法知道对方的 MAC 地址,必须通过网关转发。

好了,看到这,就有人想要问了,什么是 MAC 地址?根据以太网规定,连入网络的所有设备,都必须具有"网卡"接口。数据包必须是从一块网卡,传送到另一块网卡。网卡的地址,就是数据包的发送地址和接收地址,这叫做 MAC 地址。每块网卡出厂的时候,都有一个全世界独一无二的 MAC 地址,长度是 48 个二进制位,通常用 12 个十六进制数表示。

什么?你仿佛在逗我,我只知道我自身网卡 MAC 地址,我怎么知道他的网卡 MAC 地址?

根据 ARP 地址解析协议,就可以解决这个问题,这里只需要知道,以太网数据包必须知道接收方的 MAC 地址,然后才能发送

🎺 ARP 地址解析协议,实现由 IP 地址得到 MAC 地址,每个主机都有一个 ARP 高速缓存,高速缓存中存放着一个在 IP 地址到硬件地址 MAC 的映射表,并且这个映射表还经常动态更新

如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射

⚠️ ARP 是解决了在同一个局域网上的主机或路由器 IP 地址和硬件地址之间的映射问题,如果不在一个局域网上,就无法解析出另一个局域网上另一主机的硬件地址

emmmm,那我知道了他的 MAC 地址,我该怎样才能把数据包准确送到接收方?

答案就是: 以太网采用了一种很"原始"的方式,它不是把数据包准确送到接收方,而是向本网络内所有计算机发送,让每台计算机自己判断,是否为接收方。这种方式就叫做 “广播”。

比如:1 号计算机向 2 号计算机发送一个数据包,同一个子网络的 3 号、4 号、5 号计算机都会收到这个包。它们读取这个包的"标头"(标头会有接收者的 MAC 地址),找到接收方的 MAC 地址,然后与自身的 MAC 地址相比较,如果两者相同,就接受这个包,做进一步处理,否则就丢弃这个包。

听着有点晕?那我再举个例子:A 班的小明向 B 班的小红表白,但是他只知道她叫小红(MAC 独一无二,不存在相同情况),不知道长相,于是给 B 班的所有同学都写了一封情书,B 班的每位同学都会收到来自小明的信,他们就会读取这封信的接收者名字,和自己的名字比较,如果两者相同,就接受这封信,不同就丢弃。

这时候你又要问了,在同一个子网络可以通过 “广播” 的形式去获得对方的 MAC 地址,可是如果两台电脑不在同一个子网络,就无法知道对方的 MAC 地址,该咋办呢?

这时候就必须通过网关转发。

不懂?那我举个例子,三年级的小红要写一封信给四年级的小张,可是不是同一个年级咋办,这时候小红发现,她的室友小 A 和小张的室友小 B 是邻居,于是她对小 A 说 :“ 喂,我把这信给你,你交给你邻居小 B,让他帮忙交给小张 ” 。最终,信交到了小张的手里。这里小 A 和小 B 就充当了网关的职责。

扯那么多,我们来个实例讲解一下,到底按下的那一瞬间发生了什么!

我们知道,发送数据包和请求,必须要知道对方的 IP 地址,可是我们现在只知道域名,不知道对方的 IP 地址咋办,这时候 DNS 就发挥作用了。


安排

DHCP 配置主机信息

  • 假设主机最开始没有 IP 地址以及其它信息,那么就需要先使用 动态主机配置协议 DHCP 来获取

  • 主机生成一个 DHCP 请求报文,并将这个报文放入具有目的端口 67 和源端口 68 的 UDP 报文段中。

  • 该报文段则被放入在一个具有广播 IP 目的地址(255.255.255.255) 和源 IP 地址(0.0.0.0)的 IP 数据报中

  • 该数据报则被放置在 MAC 帧中,该帧具有目的地址 FF:FF:FF:FF:FF:FF,将广播到与交换机连接的所有设备。

  • 连接在交换机的 DHCP 服务器收到广播帧之后,不断地向上分解得到 IP 数据报、UDP 报文段、DHCP 请求报文,之后生成 DHCP ACK 报文,该报文包含以下信息:IP 地址、DNS 服务器的 IP 地址、默认网关路由器的 IP 地址和子网掩码。该报文被放入 UDP 报文段中,UDP 报文段有被放入 IP 数据报中,最后放入 MAC 帧中

  • 该帧的目的地址是请求主机的 MAC 地址,因为交换机具有自学习能力,之前主机发送了广播帧之后就记录了 MAC 地址到其转发接口的交换表项,因此现在交换机就可以直接知道应该向哪个接口发送该帧。

  • 主机收到该帧后,不断分解得到 DHCP 报文。之后就配置它的 IP 地址、子网掩码和 DNS 服务器的 IP 地址,并在其 IP 转发表中安装默认网关。

ARP 解析 MAC 地址

  • 主机通过浏览器生成一个 TCP 套接字,套接字向 HTTP 服务器发送 HTTP 请求。为了生成该套接字,主机需要知道网站的域名对应的 IP 地址。比如我们在浏览器中输入 : www.baidu.com 之后,会给 DNS 服务器发送一个 DNS 数据包,告诉 DNS : “喂,我要访问 www.baidu.com,你把他的 IP 地址给我”

  • 主机生成一个 DNS 查询报文,该报文具有 53 号端口,因为 DNS 服务器的端口号是 53。

  • 该 DNS 查询报文被放入目的地址为 DNS 服务器 IP 地址的 IP 数据报中。

  • 该 IP 数据报被放入一个以太网帧中,该帧将发送到网关路由器。

  • DHCP 过程只知道网关路由器的 IP 地址,为了获取网关路由器的 MAC 地址,需要使用 ARP 协议。

  • 主机生成一个包含目的地址为网关路由器 IP 地址的 ARP 查询报文,将该 ARP 查询报文放入一个具有广播目的地址(FF:FF:FF:FF:FF:FF)的以太网帧中,并向交换机发送该以太网帧,交换机将该帧转发给所有的连接设备,包括网关路由器。

  • 网关路由器接收到该帧后,不断向上分解得到 ARP 报文,发现其中的 IP 地址与其接口的 IP 地址匹配,因此就发送一个 ARP 回答报文,包含了它的 MAC 地址,发回给主机。

DNS 解析域名

DNS 域名解析过程,如何查找呢?第一种: 采用递归查询,如果主机查询的本地域名服务器不知道被查询域名的 IP 地址,那么本机域名服务器就以 DNS 客户的身份,向其他根域名服务器继续发出从查询请求报文(替主机查询,而不是让主机自己查询),第二种: 采用迭代查询,当根域名服务器收到本地域名服务器发出的迭代查询请求报文后,要么给出查询结果,要么就告诉本地服务器接下来应当向哪个域名服务器查询(让主机自己去查,而不是帮主机查)

  • 知道了网关路由器的 MAC 地址之后,就可以继续 DNS 的解析过程了。

  • 网关路由器接收到包含 DNS 查询报文的以太网帧后,抽取出 IP 数据报,并根据转发表决定该 IP 数据报应该转发的路由器。

  • 因为路由器具有内部网关协议(RIP、OSPF)和外部网关协议(BGP)这两种路由选择协议,因此路由表中已经配置了网关路由器到达 DNS 服务器的路由表项。

  • 到达 DNS 服务器之后,DNS 服务器抽取出 DNS 查询报文,并在 DNS 数据库中查找待解析的域名。

  • 找到 DNS 记录之后,发送 DNS 回答报文,将该回答报文放入 UDP 报文段中,然后放入 IP 数据报中,通过路由器反向转发回网关路由器,并经过以太网交换机到达主机。

如何判断是否同一网络,通过将 IP 地址和子网掩码进行逐位的“与”运算。也就是做一个二进制的 AND 运算(两个数位都为 1,结果为 1,否则为 0)

HTTP 请求页面,TCP 三次握手

  • 有了 HTTP 服务器的 IP 地址之后,主机就能够生成 TCP 套接字,该套接字将用于向 Web 服务器发送 HTTP GET 报文。

  • 在生成 TCP 套接字之前,必须先与 HTTP 服务器进行三次握手来建立连接。生成一个具有目的端口 80 的 TCP SYN 报文段,并向 HTTP 服务器发送该报文段。

  • HTTP 服务器收到该报文段之后,生成 TCP SYNACK 报文段,发回给主机。

  • 连接建立之后,浏览器生成 HTTP GET 报文,并交付给 HTTP 服务器。通过 TCP 协议,将 HTTP 请求的内容获取。也就是 TCP 数据包 + 嵌入 HTTP 的数据包。TCP 数据包再嵌入到 IP 数据包。IP 数据包需要设置双方的 IP 地址,IP 数据包嵌入以太网数据包。以太网数据包需要设置双方的 MAC 地址(通过 ARP 协议得到),通过物理层二进制数据传输,到了服务器接收方

  • HTTP 服务器接收之后,不断分解,然后从 TCP 套接字读取 HTTP GET 报文,生成一个 HTTP 响应报文,将 Web 页面内容放入报文主体中,发回给主机。

  • 浏览器收到 HTTP 响应报文后,抽取出 Web 页面内容,之后进行渲染,显示 Web 页面。

web 页面显示

  • 浏览器渲染引擎获取到请求文档的内容,将 HTML 解析成 DOM Tree,将 CSS 解析成 CSS Rule Tree,然后构建 Render Tree 有了 Render Tree 之后,接着布局 Render Tree,浏览器已知道网页有哪些节点,各节点的 CSS 定义以及它们的从属关系,去计算每个节点在屏幕中的位置。,然后绘制 render tree。

  • 在构建 CSSOM 树时,会阻塞渲染,直至 CSSOM 树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选择器,执行速度越慢。

  • 当 HTML 解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件。并且 CSS 也会影响 JS 的执行,只有当解析完样式表才会执行 JS,所以也可以认为这种情况下,CSS 也会暂停构建 DOM。