跨域问题和前端攻击
常见的web前端攻击方式有哪些
XSS
Cross Site Script跨站脚本攻击- 手段:黑客将JS代码插入到网页内容中,渲染时执行
JS代码 - 预防:特殊字符串替换(前端或后端)
CSRF
Cross Site Request Forgery跨站请求伪造- 手段:黑盒诱导用户去访问另一个网站的接口,伪造请求
- 预防:严格的跨域限制 + 验证码机制
- 判断
referer - 为
cookie设置sameSite属性,禁止第三方网页跨域的请求能携带上cookie - 使用
token - 关键接口使用短信验证码
- 判断
注意:偷取
cookie是XSS做的事,CSRF的作用是借用cookie,并不能获取cookie
CSRF攻击攻击原理及过程如下:
- 用户登录了
A网站,有了cookie - 黑盒诱导用户到
B网站,并发起A网站的请求 A网站的API发现有cookie,会在请求中携带A网站的cookie,认为是用户自己操作的
点击劫持
- 手段:诱导界面上设置透明的
iframe,诱导用户点击 - 预防:让
iframe不能跨域加载
DDOS
Distribute denial-of-service分布式拒绝服务- 手段:分布式的大规模的流量访问,使服务器瘫痪
- 预防:软件层不好做,需硬件预防(如阿里云的
WAF购买高防)
SQL注入
- 手段:黑客提交内容时,写入
sql语句,破坏数据库 - 预防:处理内容的输入,替换特殊字符
跨域方案
JSONP
利用
<script>标签没有跨域限制的漏洞。通过<script>标签指向一个需要访问的地址并提供一个回调函数来接收数据
<script src="http://domain/api?param1=a¶m2=b&callback=jsonp"></script>
- 在开发中可能会遇到多个
JSONP请求的回调函数名是相同的,这时候就需要自己封装一个JSONP,以下是简单实现
function jsonp(url, jsonpCallback, success) {let script = document.createElement("script");script.src = url;script.async = true;script.type = "text/javascript";window[jsonpCallback] = function(data) {success && success(data);};document.body.appendChild(script);
}
jsonp("http://xxx","callback",function(value) {console.log(value);}
);
CORS跨域资源共享
方案依赖服务端/后端在响应头中添加
Access-Control-Allow-*头,告知浏览器端通过此请求。只要后端实现了CORS,就实现了跨域
CORS 将请求分为简单请求(Simple Requests)和需预检请求(Preflighted requests)
-
简单请求:不会触发预检请求的称为简单请求。当请求满足以下条件时就是一个简单请求:
-
请求方法:
GET、HEAD、POST。 -
请求头:
Accept\Accept-Language、Content-Language、Content-TypeContent-Type仅支持:application/x-www-form-urlencoded、multipart/form-data、text/plain
-
-
需预检请求:当一个请求不满足以上简单请求的条件时,浏览器会自动向服务端发送一个
OPTIONS请求,通过服务端返回的Access-Control-Allow-*判定请求是否被允许
CORS 引入了以下几个以 Access-Control-Allow-* 开头:
Access-Control-Allow-Origin表示允许的来源Access-Control-Allow-Methods表示允许的请求方法Access-Control-Allow-Headers表示允许的请求头Access-Control-Allow-Credentials表示允许携带认证信息
nginx反向代理
nginx 配置跨域,可以为全局配置和单个代理配置(两者不能同时配置)
-
全局配置,在
nginx.conf文件中的http节点加入跨域信息 -
局部配置(单个代理配置跨域), 在路径匹配符中加入跨域信息
Node 中间层接口转发
Proxy
如果是通过vue-cli脚手架工具搭建项目,我们可以通过webpack为我们起一个本地服务器作为请求的代理对象
通过该服务器转发请求至目标服务器,得到结果再转发给前端,但是最终发布上线时如果web应用和接口服务器不在一起仍会跨域
在vue.config.js文件,新增以下代码
module.exports = {devServer: {host: '127.0.0.1',port: 8080,open: true,// vue项目启动时自动打开浏览器proxy: {'/api': { // '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的target: "http://xxx.xxx.xx.xx:8080", //目标地址,一般是指后台服务器地址changeOrigin: true, //是否跨域pathRewrite: { // pathRewrite 的作用是把实际Request Url中的'/api'用""代替'^/api': "" }}}}
}
通过axios发送请求中,配置请求的根路径
axios.defaults.baseURL = '/api'
websocket
利用webSocket来进行非同源之间的通信
原理:利用
webSocket的API,可以直接new一个socket实例,然后通过open方法内send要传输到后台的值,也可以利用message方法接收后台传来的数据。后台是通过new WebSocket.Server({port:3000})实例,利用message接收数据,利用send向客户端发送数据。
document.domain(不常用)
-
该方式只能用于二级域名相同的情况下,比如
a.test.com和b.test.com适用于该方式。 -
只需要给页面添加
document.domain = 'test.com'表示二级域名都相同就可以实现跨域 -
自
Chrome 101版本开始,document.domain将变为可读属性,也就是意味着上述这种跨域的方式被禁用跨域与图片
前端项目在图片处理时可能会遇到图片绘制到
Canvas上之后却不能读取像素或导出base64的问题。这个问题也是由同源策略引起。解决方式和上文相同,给图片添加crossorigin="anonymous"并在返回的图片文件响应头加上Access-Control-Allow-Origin: *即可解决
