Java八股文——计算机网络「网络攻击篇」
什么是DDoS攻击?怎么防范?
面试官您好,DDoS攻击,全称是分布式拒绝服务攻击(Distributed Denial-of-Service),它是目前互联网上最常见、也最具破坏力的网络攻击方式之一。
1. DDoS攻击的本质是什么?
- 核心目标:DDoS攻击的目的,不是窃取数据,而是通过消耗目标系统的某一种或多种关键资源,使其不堪重负,最终无法为正常用户提供服务。
- “分布式”是其关键:与传统的DoS攻击(由单个攻击源发起)不同,DDoS的“分布式”特性,意味着攻击流量来自成千上万个、分布在全球各地的、被恶意软件控制的“僵尸主机”(Botnet)。
- 为什么难以防御? 由于每一个攻击源都是一个看似“合法”的互联网设备,这使得区分攻击流量和正常流量变得极其困难。
2. 常见的DDoS攻击类型(按网络层次划分)
DDoS攻击可以发生在网络协议栈的各个层面,每一种都针对一种特定的资源。您的分类非常专业:
-
a. 网络层/传输层攻击 (带宽/连接耗尽型)
- 目标:耗尽服务器的网络带宽或连接处理能力。
- 典型攻击:
- SYN Flood:伪造大量
SYN
请求,打满服务器的TCP半连接队列。 - UDP Flood / 反射攻击 (如NTP Flood):发送大量的UDP数据包,直接塞满服务器的网络带宽。
- ACK Flood / 连接耗尽攻击:建立大量“空闲”的TCP连接,耗尽服务器的连接表资源。
- SYN Flood:伪造大量
-
b. 应用层攻击 (资源/性能耗尽型)
- 目标:耗尽服务器的CPU、内存或应用处理能力。这类攻击更隐蔽,流量可能不大,但“杀伤力”极强。
- 典型攻击:
- HTTP Flood:模拟大量正常用户,发送海量的HTTP请求(比如不断请求一个需要复杂数据库查询的API),耗尽Web服务器或数据库的性能。
- 慢速连接攻击 (Slowloris):与服务器建立一个连接,然后以极慢的速度发送HTTP请求,长时间地、廉价地占用一个连接,最终耗尽服务器的连接池。
- SSL/TLS连接攻击:利用HTTPS握手时非对称加解密的巨大计算开销,发起大量SSL握手请求,耗尽服务器的CPU资源。
3. 如何防范DDoS攻击?—— 一个多层次的纵深防御体系
防御DDoS,不可能依靠单一的技术,必须构建一个从网络基础设施到应用层的、多层次的纵深防御体系。
-
第一层:基础设施与网络层防御
- 增加带宽:最简单粗暴但有效的方式,直接提升服务器的网络带宽,提高被“灌满”的门槛。
- 硬件防火墙与入侵检测/防御系统 (IDS/IPS):在网络入口处,通过硬件设备,根据规则(如IP黑名单、流量异常模型)对流量进行初步过滤。
- 使用专业的DDoS防护服务 (流量清洗):这是最核心、最有效的防御手段。当检测到攻击时,将所有流量牵引到云服务商的“清洗中心”。清洗中心会利用其海量的带宽和专业的设备,识别并丢弃恶意流量,然后再将干净的、合法的流量,回注给我们的服务器。
-
第二层:服务器与系统层防御
- 优化内核参数:针对SYN Flood等攻击,可以优化Linux的TCP/IP协议栈参数(如开启
syncookies
、增大半连接队列、减少重传次数等)。 - 限制连接数与速率:在Nginx等Web服务器上,配置连接频率限制和并发连接数限制(如
limit_req
,limit_conn
),防止单个IP发起过多请求。
- 优化内核参数:针对SYN Flood等攻击,可以优化Linux的TCP/IP协议栈参数(如开启
-
第三层:应用层防御
- 识别与拦截:通过WAF(Web应用防火墙),对HTTP请求进行更深入的分析,识别并拦截恶意的HTTP Flood攻击。
- 代码层面优化:对应用中计算成本高的接口,增加缓存,减少其对后端资源的消耗。
- 增加验证码:在关键接口(如登录、注册)增加人机验证,可以有效防御自动化的脚本攻击。
总结一下,DDoS攻击是一种利用 “不对称性”(攻击者用很小的成本,让被攻击者付出巨大的资源代价)的攻击方式。我们的防御策略,也必须是立体的、多层次的,从购买专业的流量清洗服务,到精细化的服务器配置,再到健壮的应用层设计,层层设防,才能有效地抵御这种威胁。
SQL注入问题是什么?
面试官您好,SQL注入是一种非常常见、也极具破坏力的Web应用程序安全漏洞。
1. SQL注入是什么,以及它如何发生?
-
根本原因:SQL注入的根源在于,应用程序将用户提供的、不可信的输入,直接拼接成了动态的SQL查询语句的一部分,然后交给数据库去执行。
-
攻击原理:攻击者通过在输入框中,提交一段精心构造的、恶意的SQL代码片段,来“欺骗”应用程序,使其最终执行的SQL语句,完全偏离了开发者原始的意图。
-
一个经典的代码示例(有漏洞的):
假设我们有一个用户登录的后端逻辑,它是这样写的:// 这是一个有严重安全漏洞的写法! String username = request.getParameter("username"); String password = request.getParameter("password");String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";ResultSet rs = statement.executeQuery(sql); // ...
-
攻击者如何利用?
- 一个普通用户,会输入用户名
"alice"
和密码"123456"
。最终执行的SQL是:
SELECT * FROM users WHERE username = 'alice' AND password = '123456'
- 而一个攻击者,他可能会在用户名字段输入
' OR '1'='1
,密码字段随便输。 - 此时,由于简单的字符串拼接,最终在数据库执行的SQL就变成了:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '... '
'1'='1'
这个条件永远为true
,导致WHERE
子句的整个条件也为true
。这条SQL最终会查询出users
表中的所有用户,攻击者就可能在没有密码的情况下,成功登录了第一个用户的账号。更严重的,攻击者还可以构造DROP TABLE
等语句,直接破坏数据库。
- 一个普通用户,会输入用户名
2. 如何防范SQL注入?
解决SQL注入,需要一套纵深的、多层次的防御策略。
-
方案一:使用参数化查询(或预编译语句)—— 最根本、最有效的解决方案
- 这是防御SQL注入的“银弹”,是必须遵守的最佳实践。
- 做法:我们不再手动拼接SQL字符串。而是使用占位符
?
来代替用户输入。 - 示例 (使用JDBC的
PreparedStatement
):String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, username); // 将用户输入作为参数设置 pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery();
- 为什么能防范?
- 核心在于它实现了 “代码”和“数据”的完全分离。
- 数据库在接收到这条SQL时,会先对不包含任何用户数据的SQL模板(
SELECT * FROM ... WHERE username = ? ...
)进行预编译,生成一个固定的执行计划。 - 然后,再将用户输入的值,作为纯粹的“参数”或“数据”,填充到这个已经定型的执行计划中去。
- 此时,即使用户输入了
' OR '1'='1
,数据库也只会把它当作一个普通的字符串"' OR '1'='1'"
去进行匹配,而绝对不会将其作为SQL语法的一部分来执行。
-
方案二:输入验证与过滤(辅助防御层)
- 做法:在接收到用户输入后,进行严格的合法性校验。
- 白名单验证:比如,如果一个参数期望是数字,就严格校验它是否只包含数字。
- 黑名单过滤:过滤掉一些高危的SQL关键字和特殊字符(如
' " ; --
等)。
- 作用:可以作为一道辅助的防线,但它不能作为唯一的防御手段,因为攻击者总可能找到绕过过滤规则的方法。
- 做法:在接收到用户输入后,进行严格的合法性校验。
-
方案三:最小权限原则(降低损害)
- 做法:为我们的Web应用,配置一个权限尽可能小的数据库账户。
- 作用:这个账户应该只拥有对业务相关表进行增删改查的权限,而绝对不能有
DROP TABLE
,TRUNCATE TABLE
等高危操作的权限。 - 效果:这是一种“纵深防御”思想。即使万一发生了SQL注入,也能将攻击者可能造成的损害,控制在最小的范围内。
-
方案四:使用成熟的ORM框架
- 像MyBatis, Hibernate, JPA等现代ORM框架,其内部都已经默认实现了参数化查询。只要我们正确地使用它们提供的API(比如MyBatis中的
#{}
占位符),就能天然地防范SQL注入。
- 像MyBatis, Hibernate, JPA等现代ORM框架,其内部都已经默认实现了参数化查询。只要我们正确地使用它们提供的API(比如MyBatis中的
总结一下,防范SQL注入,使用参数化查询(或PreparedStatement
)是必须遵守的黄金法则。在此基础上,再配合严格的输入验证和数据库最小权限原则,就能构建一个安全、健壮的数据库访问层。
CSRF攻击是什么?
面试官您好,CSRF,全称是Cross-Site Request Forgery(跨站请求伪造),它是一种非常常见的、利用了浏览器对Cookie的自动发送机制的Web攻击方式。
1. CSRF攻击是如何发生的?—— 一个生动的例子
要理解CSRF,我们先来看一个典型的攻击场景:
- 前提:用户小明已经登录了
www.mybank.com
银行网站,并且他的浏览器中,保存了银行网站的登录Cookie。他没有退出登录,只是关闭了网页。 - 诱导:攻击者在一个恶意网站(比如
www.hacker.com
)上,放置了一个看似无害的图片或链接,但其背后指向的是一个银行的转账API。<!-- 恶意网站上的图片 --> <img src="http://www.mybank.com/transfer?to=hacker&amount=10000" style="display:none;">
- 触发:小明在保持着银行登录状态的情况下,访问了这个恶意网站。
- 浏览器“助纣为虐”:当浏览器尝试加载这个
<img>
标签的src
时,它会向www.mybank.com
发起一个GET请求。最关键的是,因为这个请求的目标是银行网站,浏览器会自动地、无差别地将本地保存的、属于mybank.com
域的那个登录Cookie,一并带上。 - 攻击成功:银行服务器收到这个请求后,它看到了合法的登录Cookie,完全无法分辨这个请求是来自小明在银行网站上的主动操作,还是来自一个恶意网站的“伪造”。它会认为这是一个合法的转账请求,并成功地将10000元转给了黑客。
总结一下,CSRF攻击的本质,就是攻击者 “借” 了用户的登录凭证(Cookie),去伪造并发送了一个用户在不知情的情况下发起的、对其自身不利的请求。
2. 如何防范CSRF攻击?
防范CSRF的核心思想,就是增加一个攻击者无法伪造的、与用户会话绑定的随机凭证。
-
方案一:使用CSRF Token(最核心、最标准的方案)
- 原理:
- 当用户访问一个需要保护的页面(如转账页面)时,服务器会生成一个随机的、一次性的Token(我们称之为CSRF Token)。
- 服务器会将这个Token,一方面存储在自己的Session中,另一方面,通过隐藏表单字段的方式,嵌入到返回的HTML页面里。
- 当用户提交这个表单时,这个隐藏的CSRF Token会随着表单数据一起被提交。
- 服务器在接收到请求后,会同时验证Cookie中的Session ID和表单中的CSRF Token。它会比较用户提交的CSRF Token,是否与自己Session中保存的那个Token一致。
- 为什么能防范?
- 攻击者虽然能伪造请求,但他无法获取到那个嵌入在用户正常页面HTML里的、随机的CSRF Token。因此,他伪造的请求中,无法包含这个正确的Token,服务器在验证时就会失败。
- 实践:现代Web框架(如Spring Security, Django)都内置了完善的CSRF Token防护机制。
- 原理:
-
方案二:验证HTTP
Referer
头部- 原理:
Referer
头部记录了请求的来源页面地址。服务器可以检查这个Referer
,确保请求是从自己信任的域名(如www.mybank.com
)发起的,而不是从www.hacker.com
发起的。 - 缺点:
- 不绝对可靠:
Referer
可以被一些浏览器或代理软件所禁用或篡改。 - 隐私问题:有些用户为了保护隐私,会主动关闭
Referer
的发送。
- 不绝对可靠:
- 原理:
-
方案三:使用
SameSite
Cookie属性(现代浏览器的利器)- 原理:这是近年来浏览器提供的一个非常强大的、从根源上解决CSRF的机制。我们可以在服务器下发Cookie时,为其设置
SameSite
属性。 - 属性值:
Strict
:最严格。浏览器在任何跨站请求中,都绝对不会携带这个Cookie。Lax
(目前很多浏览器的默认值):在一个相对宽松的模式。对于一些顶级的、会改变URL的导航请求(如链接点击、GET
表单),允许携带Cookie,但对于一些“危险”的跨站请求(如POST
表单、iframe
、img
标签等),则不会携带。None
:关闭SameSite
防护,允许所有跨站请求携带Cookie(必须配合Secure
属性)。
- 效果:通过将Cookie设置为
SameSite=Strict
或Lax
,我们就可以让浏览器自动地帮助我们阻止来自恶意网站的CSRF攻击。
- 原理:这是近年来浏览器提供的一个非常强大的、从根源上解决CSRF的机制。我们可以在服务器下发Cookie时,为其设置
总结与我的实践:
在我的项目中,我会采用 “纵深防御” 的策略:
- 首先,我会将核心认证Cookie的
SameSite
属性设置为Lax
或Strict
,这是最有效、最底层的防御。 - 其次,我依然会启用框架自带的CSRF Token机制,作为第二道坚实的防线。
- 最后,对于一些极其敏感的操作,我可能还会要求用户再次输入密码或进行二次验证。
通过这套组合拳,就能非常有效地防范CSRF攻击。
XSS攻击是什么?
面试官您好,XSS,全称是Cross-Site Scripting(跨站脚本攻击),它是Web安全领域最古老、也最常见的一种注入型攻击。
1. XSS攻击的本质是什么?
- XSS攻击的本质,是攻击者想方设法地,将一段恶意的JavaScript脚本,注入到了一个正常的、受信任的网页中。
- 当其他用户访问这个被“污染”的网页时,这段恶意脚本就会在用户的浏览器中执行。
- 由于浏览器对来自同一源的脚本是完全信任的,所以这段恶意脚本,就可以为所欲为,比如:
- 窃取用户的Cookie,从而冒用用户身份。
- 监听用户的键盘输入,获取密码等敏感信息。
- 将用户重定向到钓鱼网站。
- 在页面上弹出虚假的登录框。
2. XSS攻击的三种主要类型
根据恶意脚本的“注入”和“触发”方式不同,XSS可以分为三种类型:
-
a. 存储型XSS (Stored XSS) —— “最危险的类型”
- 攻击流程:
- 攻击者在一个允许用户输入并会保存到数据库的地方(比如文章评论区、用户个人资料),提交了一段包含恶意脚本的内容。
- 服务器未经过滤,就将这段恶意内容存储到了数据库中。
- 当任何一个正常用户访问这个页面时(比如查看这篇文章的评论),服务器会从数据库中取出这段恶意内容,并将其作为正常HTML的一部分,返回给用户的浏览器。
- 浏览器在渲染页面时,就会执行这段恶意脚本。
- 危害:它的危害最大,因为恶意脚本被永久地存储在了服务器上,任何访问这个页面的用户,都会受到攻击。
- 攻击流程:
-
b. 反射型XSS (Reflected XSS) —— “一次性的诱骗”
- 攻击流程:
- 攻击者构造一个包含了恶意脚本的URL。
- 然后,通过社交网络、邮件等方式,诱骗用户去点击这个链接。
- 当用户点击后,恶意脚本作为URL的一部分,被发送到了服务器。
- 服务器未经过滤,就从URL中提取出这段恶意脚本,并将其拼接到返回的HTML页面中(比如在一个搜索结果页面或错误提示页面中,回显用户的输入)。
- 浏览器在渲染这个响应页面时,就会执行这段恶意脚本。
- 危害:它是一次性的,只对点击了特定恶意链接的用户有效。
- 攻击流程:
-
c. DOM型XSS (DOM-based XSS) —— “前端的自我攻击”
- 攻击流程:这是一种更隐蔽的类型。它的整个攻击过程,可能完全不经过服务器。
- 攻击者同样是构造一个包含恶意脚本的URL(比如在URL的
#
片段中)。 - 当用户访问这个URL时,页面的前端JavaScript代码,在处理这个URL、动态修改页面DOM结构时,不慎将URL中的恶意脚本,作为HTML的一部分,写入到了页面中。
- 这同样会导致恶意脚本被执行。
- 攻击者同样是构造一个包含恶意脚本的URL(比如在URL的
- 特点:服务器可能自始至终都没有收到过这段恶意代码,漏洞完全出在前端JS对DOM的不安全操作上。
- 攻击流程:这是一种更隐蔽的类型。它的整个攻击过程,可能完全不经过服务器。
3. 如何防范XSS攻击?—— 纵深防御原则
防御XSS,需要遵循一个核心原则:永远不要信任任何用户的输入。我们需要建立一个多层次的纵深防御体系。
-
1. 输入验证与过滤 (Input Validation)
- 做法:在接收到任何用户输入时(无论是在前端还是后端),都应该进行严格的合法性校验。比如,限制输入的长度、格式(如邮箱、手机号),并过滤掉一些明显的、危险的HTML标签和JS事件处理器。
- 作用:作为第一道防线,但不能完全依赖它。
-
2. 输出编码/转义 (Output Encoding) —— 最核心、最有效的防御
- 这是防御XSS的“银弹”。
- 做法:当我们需要将用户输入的内容,再显示到页面上时,必须对这些内容进行HTML实体编码。
- 效果:比如,用户输入的
<script>alert(1)</script>
,在输出到HTML时,应该被转义成<script>alert(1)</script>
。 - 这样,浏览器在解析时,只会把它们当作普通的文本来显示,而绝对不会将其作为HTML标签或脚本来执行。
- 现代的前端框架(如React, Vue)默认都会对输出进行自动转义,大大提升了安全性。
-
3. 设置内容安全策略 (Content Security Policy, CSP)
- 做法:通过在HTTP响应头中,设置
Content-Security-Policy
,来告诉浏览器一个加载资源的“白名单”。 - 效果:比如,我们可以规定,这个页面只允许加载来自本域名和我方CDN的脚本。这样,即使攻击者成功地注入了指向他自己服务器的恶意脚本,浏览器也会因为其来源不在白名单内,而拒绝加载和执行它。
- 做法:通过在HTTP响应头中,设置
-
4. 设置
HttpOnly
Cookie- 这是一个 “减损” 措施。
- 做法:在设置关键的认证Cookie时,加上
HttpOnly
属性。 - 效果:这使得这个Cookie无法被任何JavaScript代码读取。即使XSS攻击发生了,攻击者也无法通过
document.cookie
来窃取到用户的Session ID,从而保护了用户的会话。
通过这套**“输入验证 + 输出编码 + CSP白名单 + HttpOnly减损”**的组合拳,我们就能非常有效地、系统地防范各类XSS攻击。
了解过DNS劫持吗?
面试官您好,我了解DNS劫持。它是一种非常常见、也极其隐蔽的网络攻击手段,其本质是一种中间人攻击。
1. DNS劫持是什么?—— “假的电话簿”
- 核心原理:DNS劫持的核心,就是攻击者通过某种手段,在DNS查询的过程中进行拦截和篡改。
- 它做什么? 当用户请求解析一个正常的域名(如
www.mybank.com
)时,攻击者会返回一个错误的、指向他自己恶意服务器的IP地址。 - 一个生动的比喻:
- DNS系统就像一个全球联网的“114查号台”。
- DNS劫持,就相当于有一个 “骗子接线员”,在你打电话问“工商银行的电话是多少?”时,他抢在真正的114之前,告诉了你一个骗子的电话号码。
- 当你满心欢喜地拨打这个号码时,接电话的就是骗子,他可以伪装成银行客服,骗取你的信息。
2. DNS劫持通常发生在哪些环节?
DNS查询的链路很长,攻击者可以在多个薄弱环节下手:
-
本地设备层面:
- 恶意软件/病毒:直接修改用户电脑的
hosts
文件,或者篡改网络设置,将DNS服务器指向一个恶意服务器。
- 恶意软件/病毒:直接修改用户电脑的
-
局域网层面:
- 路由器被入侵:攻击者控制了用户家里的或公司里的路由器,然后修改路由器的DNS设置,将所有流经该路由器的DNS查询,都转发到恶意的DNS服务器上。
- 公共Wi-Fi陷阱:连接一个不安全的、由攻击者设置的公共Wi-Fi,是DNS劫持的重灾区。
-
网络运营商(ISP)层面:
- 这是最常见的一种“良性”劫持,也叫 “DNS污染”。一些地方的运营商,为了投放广告或其他目的,会拦截对某些不存在的域名的查询,并将其重定向到一个广告页面。
-
DNS服务器本身被攻击:
- 攻击者通过漏洞,直接入侵了某个公共的DNS服务器,并篡改了其中的缓存记录。
3. 如何防范DNS劫持?
防范DNS劫持,需要从客户端、传输过程、服务器端多个层面入手。
-
1. 对于普通用户:
- 使用更可靠的公共DNS:不要使用运营商默认的DNS。手动将DNS服务器设置为一些声誉良好的公共DNS,如Google的
8.8.8.8
,Cloudflare的1.1.1.1
,或者国内的DNSPod119.29.29.29
。这些DNS服务通常有更好的安全防护。 - 定期检查
hosts
文件,警惕不安全的公共Wi-Fi。
- 使用更可靠的公共DNS:不要使用运营商默认的DNS。手动将DNS服务器设置为一些声誉良好的公共DNS,如Google的
-
2. 对于Web服务提供商(我们开发者能做的):
-
核心方案:全面启用HTTPS
- 即使DNS劫持让用户访问到了一个错误的IP地址,但由于攻击者没有我们网站域名的私钥,所以他无法提供一个有效的、受信任的HTTPS证书。
- 当用户的浏览器尝试与这个假冒的服务器进行HTTPS握手时,会立刻发现证书无效,并向用户弹出非常严厉的安全警告,从而阻止用户继续访问,保护了用户安全。
- 所以,HTTPS是防范DNS劫劫持后“钓鱼”行为的最后一道、也是最坚固的一道防线。
-
DNSSEC (DNS Security Extensions)
- 这是一种更底层的、从DNS协议本身解决问题的技术。它通过对DNS记录进行数字签名,来保证DNS响应的真实性和完整性,防止其被篡改。
- 目前,DNSSEC的普及率还在逐步提升中。
-
总结一下,DNS劫持通过污染DNS解析结果,将用户引向恶意网站。作为普通用户,我们可以通过更换为更安全的公共DNS来防护;而作为服务提供方,部署全站HTTPS,是保护我们的用户免受DNS劫持后续危害的最有效、最根本的手段。
参考小林 coding