大家好,我是沐华。最近面了一些前端,发现每次问到安全相关的问题,一些面试者只能说上来 XSS、CSRF、中间人攻击,就没了,于是写了这篇文章,总结了前端安全相关的点,给大家查缺补漏
浏览器
XSS
XSS
攻击是一种代码注入攻击,通过恶意注入脚本在浏览器运行,然后盗取用户信息。本质上其实是因为网站没有过滤恶意代码,与正常代码混在一起之后,浏览器没有办法分辨哪些是可信的,然后导致恶意代码也被执行
结果是可能会导致:页面数据或用户信息被窃取、伪造登录窗口或在页面生成浮窗广告、监听键盘事件窃取账号密码、流量被支持到其他网站等
XSS
攻击有三种类型:
- 存储型:通过输入框把恶意代码提交到网站数据库中,然后比如在显示评论的页面就会从数据获取,并直接执行
- 反射型:和存储型不同的是不会储存在服务器里。比如打开包含带恶意脚本的链接,当打开后会向服务器请求后,服务器会获取URL中的数据然后拼接在HTML上返回,然后执行
- 基于DOM型:是通过一些劫持手段,在页面资源传输过程中劫持并修改页面的数据,插入恶意代码
防范:比如对输入框内容进行过滤和用转义符进行转码、添加白名单、关闭 Cookie 访问权限、使用验证码防止脚本伪装成用户执行操作等
CSRF
CSRF
就是跨站请求伪造攻击,主要就是利用用户的登录状态发起跨站请求
比如邮箱里的乱七八糟的链接,打开链接的时候邮箱肯定是处于登录状态,然后黑客就可以用这个登录状态,伪造带有正确 Cookie
的 http
请求,直接绕过后台的登录验证,然后冒充用户执行一些操作,本质是利用 Cookie
在同源请求中携带发送给服务器的特点,来实现冒充用户
发起 CSRF
攻击有几个必要条件:
- 目标网站一定要有
CSRF
漏洞 - 用户登录过目标网站,并且浏览器保存了登录状态
- 需要用户主动打开第三方站点
CSRF
攻击也有三种类型:
- 自动发GET类型:比如
img
或iframe
标签等,当用户打开这个网站时会自动发起带Cookie
的资源请求 - 自动发POST类型:比如整一个隐藏的
表单
,在用户进入页面的时候自动提交表单 - 诱导链接型:就是诱导用户主动点击链接,比如
a标签
防范:比如 Token
验证、双重 Cookie
、通过 origin/referer
验证请求来源等
CSP
CSP
就是白名单,作用是可以禁止加载外域的代码,禁止外域的提交,只允许本域下的请求表单提交之类的,简单说就是告诉浏览器哪些资源可以加载执行,让那些真的插入进入的恶意代码也不会被执行;或者允许向哪些第三方站点提交数据,因为攻击者窃取信息的根本还是向外域提交
开启 CSP
的方式有两种
1. meta
2. http request header
如果不支持 Content-Security-Policy
,可以用 X-XSS-Proterction
代替
# 所加载的内容必须来自同源站点
Content-Security-Policy: default-src "self"
# 添加可信域名
Content-Security-Policy: *.baidu.com
# 和上面同理
Content-Security-Policy-Report-Only: policy
HSTS
HSTS
是 HTTP
严格传输安全协议,作用是强制客户端使用 https
与服务器建立连接,以避免因为 http
而被中间人攻击
HSTS
设置须添加在请求头中,如下
Strict-Transport-Security: max-age=12345;includeSubDomains;
参数:
- max-age: 指定该设置过期的时间,单位毫秒
- includeSubDomains: 可选参数,表示所有子域名也必须通过
https
访问 - preload: 可选参数,可以设置一个使用
https
的域名列表
设置 HSTS
后,再使用 http
访问时,只要 max-age
没有过期,客户端内部会进行跳转,会出现 307 Redirect Internel
状态码,变成 https
后,再访问请求的资源服务器
X-Frame-Options
X-Frame-Options
是用于控制当前页面是否可以被嵌入到 iframe
中,以防盗链及点击劫持攻击
X-Frame-Options
设置须添加在请求头中,如下
X-Frame-Options: DENY
参数:
- DENY: 不允许,同域名嵌套也不行
- SAMEORIGIN: 允许同域名嵌套
- ALLOW_FORM url: 可以指定允许嵌套访问的来源
设置 X-Frame-Options
后,可以确保我们的网站没有被嵌入到别人的站点里去(以防内容被恶意嵌套,并且在表面加一个透明层,诱导用户点击),从而避免点击劫持攻击及恶意盗链
SRI
SRI
指子资源完整性,该方案的作用是确保我们站点的资源文件永远不会被改变,如果被改变,浏览器会拒绝执行
比如我们打包的时候有一个 xxx.js
文件,被 index.html
引用,并上传 CDN
,用户在访问的时候,会去请求 xxx.js
,而这个文件可能被劫持篡改,或者由于网络等原因,接收到的文件不完整,怎么办?
而设置了 SRI
就可以确保当请求的文件被篡改或不完整的时候就拒绝执行该文件,设置如下:
标签上的 intergrity
属性值的格式是:哈希算法/base64后的哈希值
原理:
打包的时候会根据文件内容生成 hash
,并且把 hash
作为 intergrity
属性注入到标签上,客户端接收到文件后,根据文件内容生成 hash
与 intergrity
上的进行对比是否一致,如果不一致就会认为是不安全的,拒绝执行
Referrer-Policy
Referrer-Policy
是一种 HTTP
安全方案,用于控制 referer
携带策略,用于监管哪些访问来源信息会在 referer 中发送
注意 referer 实际上是单词 referrer 的错误拼写。而 Referrer-Policy 这个首部并没有延续这个错误拼写
开启 Referrer-Policy
的方式有两种
1. meta
2. http general
Referrer-Policy: same-origin
参数:
- no-referrer:不发送
referer
- no-referrer-when-downgrade:默认值,同安全级别发送
referrer
并且是完整url
,不同安全级别则不发送 - origin:只发送协议、域名、端口,不发送完整
url
,比如https://juejin.cn/index.html
,会变成https//juejin.cn/
- origin-when-cross-origin:同源才发送完整
url
,不同源只发送协议、域名、端口 - same-origin:同源才发送
referer
,并且是完整的url
- strict-origin:同安全级别和
origin
是一样的,比如https
请求https
,如https
请求http
是不同安全级别了,就不发送 - strict-origin-when-cross-origin:同源发送完整
url
,同安全级别才发送协议、域名、端口,不同源或不同安全级别不发送referer
- unsafe-url:这是最不安全的策略,不管同不同源都发送完整
url
HTTPS
由于 http
是明文传输,是不安全的,所以在 http
传输过程中信息可能被窃取、伪造、篡改,这种攻击方式被称为中间人攻击
避免中间人攻击的方法就是用 https
,在应用层与传输层之间添加一个安全层 TLS
,但也不是就绝对安全了
安全层会通过加密算法和公钥私钥加密传递的数据,好处是即使被劫持,中间人没有私钥就拿不到加密生成的随机数,就无法生成最终密钥
但问题是:假如一开始就被 DNS
劫持,或者说域名劫持攻击,拿到的公钥就是中间人的,中间人解密拿到数据后,再请求实际服务器,拿到服务器公钥,再把信息发给服务器,这样不知不觉间信息还是会被窃取
所以,还需要搭配数字证书,来帮我们验证服务器身份。可 https
还有一个安全问题就是伪造证书的存在,比如
- 比如
CA
机构没有正确校验申请者的身份而无意签发了一些错误的证书 - 比如
CA
机构在利益的驱使下,发放的证书 - 比如冒充或伪造某个域名的拥有者,申请到一张证书,毕竟域名拥有者是无法知晓哪些
CA
机构给他签发了证书,也不知道是否有人冒充他的身份申请了证书的 - ...
而 CA
证书公钥可信度是靠操作系统里面预置的 CA
证书公钥列表来保证的,就像白名单,用户一般也不知道 CA
证书公钥的真假,那如果有黑客有能力把自己的公钥放到用户系统的 CA
证书公钥列表里,那也可以伪造数字证书放到用户的电脑上,而用户却无法感知就信任了这个证书,然后你懂的
为了解决证书问题,有一个解决方案,就是证书透明度(CT
),能够审计、监控证书的签发和使用,一旦发现伪造的证书,可以快速联系到 CA
机构,吊销该证书
使用证书透明度服务就是添加请求头 Expect-CT
用来告诉浏览器期望使用证书透明度服务的,这能更有效的避免中间人攻击等
但谁也不能说这就有 100% 的绝对安全了,只是现行架构下的这些解决方案,已经大大增加了中间人的攻击成本,一般都是可以放心的
Node(服务端)
本地文件操作
指由于本地文件操作相关或路径拼接导致的文件资源泄露,所带来的安全问题
- 比如提供了一个静态服务,通过请求的参数 url 来给客户端返回想要资源,而用户手动修改 url 上的路径却可以访问到
- 比如暴露了一个服务或接口也可以操作文件的话,如果对它的校验不是那么安全的,就会有攻击者能访问到我们的文件,比如 ssh 文件、密码之类的
预防:express-static
、koa-static
、resolve-path
,都可以解决这个
WebShell
WebShell
是指一种恶意脚本,或者脚本木马
原理:
利用文件上传漏洞、SQL注入漏洞等等,把恶意文件放到服务器中,作为后门,然后通过服务器开放的端口+后门获取服务器的操作权限,比如窃取用户数据、修改权限、文件管理 修改甚至删除 web 页面、数据库管理等等
常见的 WebShell
编写语言是 jsp、asp、php
攻击方式:
- 上传漏洞。网站上有上传文件的功能,过滤又不严,就可以直接把
jsp、asp、php
文件直接上传到服务器 - 上传文件类型。项目上有添加上传类型或重命名文件功能的,比如把
WebShell
文件重命名成.jpg之类的允许上传的文件,上传完成后,再重命名改回如.jsp
这样类型的文件 - 隐藏到合法文件。比如把
php
代码放到jpg
文件里,再使用@运算符防止发生错误,或者删除空格换行等,导致代码比较混乱,再使用编码或者加密来隐藏恶意函数等 - 隐藏到日志。修改发送数据包的头部,添加
WebShell
。 web 服务器一般会保存访问记录到Web日志,如果找到web日志,且放到可执行目录下,可能获得 shell - .....
ReDos
ReDos
就是正则表达式攻击,利用正则表达式攻击或者利用开发者正则写的不规范,而疯狂占用服务器资源,造成服务器宕机
正则表达式匹配规则是:会先匹配第一种要能性,每当一次匹配不成功,就会尝试回溯到上一个字符,看看能不能有其他组合来匹配到这个字符串,比如,匹配 aaa
会向下面这样匹配
aaa
aa + a
a + aa
a + a + a
再看下图三条正则表达式执行时间,第一条 0.198ms
,第二条 26.445ms
,第三条没有结果,因为跑不完,会一直疯狂占用资源
时序攻击
时序攻击由于条件非常严荷,所以了解一下即可,哪怕只能说出时序攻击这四个字,但知道有这么回事就比不知道的强
比如攻击者尝试 arr = [1,2]
、arr = [1,3]
,发现响应时间几乎一致,则可以认为第一个数字不是 1
,再尝试 arr = [2,1]
,依此类推,不断碰撞尝试,直到最后碰撞出来真实的 arr
像是对比两个数组是否相同,下面代码看似没什么问题,业务效果完全能达到,但是在绝对安全层面上是不安全的
当然业务代码中没必要这么严苛,因为比如上述代码上如果还有其他 if else
判断,就完全没办法碰撞出来了
爬虫
爬虫就是一种按照一定规则自动抓取资源的程序或者脚本,搜索引擎可以用爬虫抓取网页、图片、视频、音频等
对于有一些没有防范的系统,通过爬虫,甚至可以把人家会员才能看或者付费下载的资源直接给爬下来,假设网站上有一个 10MB
的文件,使用爬虫抓取上千上万次,就会导致网站产生大量出站流量,很可能还会使服务器瘫痪无法访问了
防范其实主要就是服务端安全校验的问题,比如设置 robots.txt 文件、比如对请求中的 User Agent 识别和限制,说到底防爬虫主要是防范这几个点:ip
、origin
、referer
、request headers
如果没有并发的去请求去爬虫的时候,它不会针对 ip
做校验,只会判断后面几个,而如果没有后几点就会认为你是不安全的系统,就给爷爬
结语
如果本文对你有一点点帮助,点个赞支持一下吧,你的每一个【赞】都是我创作的最大动力 ^_^
更多前端文章,或者加入前端交流群,欢迎关注公众号【沐华说技术】,大家一起共同交流和进步呀