跨域,同源策略

跨域,同源策略跨域问题涉及到 WEB 网页安全性问题 使用不当会造成用户隐私泄露风险 但有时业务上又需要进行跨域请求 如何正确的使用跨域功能 既能满足业务需求 又能够满足安全性要求 显得尤为重要 1 1 同源策略协议相同 域名相同 端口相同同源策略限制内容有 Cookie LocalStorage IndexedDB 等存储性内容 DOM 节点 AJAX 请求发送后 结果被浏览器拦截了同源政策的目的 是为了保证用户信息的安全 防止恶意的网站窃取数据 1 2 为什么要有跨域限制 Ajax 的同源策

        跨域问题涉及到WEB网页安全性问题,使用不当会造成用户隐私泄露风险,但有时业务上又需要进行跨域请求。如何正确的使用跨域功能,既能满足业务需求,又能够满足安全性要求,显得尤为重要。

1.1.同源策略

  • 协议相同
  • 域名相同
  • 端口相同

同源策略限制内容有:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

        1.2.为什么要有跨域限制

Ajax 的同源策略主要是为了防止 CSRF(跨站请求伪造) 攻击,如果没有 AJAX 同源策略,相当危险,我们发起的每一次 HTTP 请求都会带上请求地址对应的 cookie,那么可以进行攻击。

其实,准确的来说,跨域机制是阻止了数据的跨域获取,不是阻止请求发送。

2.浏览器跨域的解决方案

        2.1.CORS标准

CORS 是一个 W3C 标准,全称是跨域资源共享(CORSs-origin resource sharing),它允许浏览器向跨源服务器,发出XMLHttpRequest请求。

                2.1.1.简单请求

只要同时满足以下两大条件,就属于简单请求

条件1:使用下列方法之一:

  • GET
  • HEAD
  • POST

条件2:Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

                2.1.2.复杂请求

不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

我们用 PUT向后台请求时,属于复杂请求,后台需做如下配置:

// 允许哪个方法访问我 res.setHeader('Access-Control-Allow-Methods', 'PUT') // 预检的存活时间 res.setHeader('Access-Control-Max-Age', 6) // OPTIONS请求不做任何处理 if (req.method === 'OPTIONS') { res.end() } // 定义后台返回的内容 app.put('/getData', function(req, res) { console.log(req.headers) res.end('我不爱你') })

接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段

// index.html
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.response)
      //得到响应头,后台需设置Access-Control-Expose-Headers
      console.log(xhr.getResponseHeader('name'))
    }
  }
}
xhr.send()
//server1.js let express = require('express'); let app = express(); app.use(express.static(__dirname)); app.listen(3000);
//server2.js let express = require('express') let app = express() let whitList = ['http://localhost:3000'] //设置白名单 app.use(function(req, res, next) { let origin = req.headers.origin if (whitList.includes(origin)) { // 设置哪个源可以访问我 res.setHeader('Access-Control-Allow-Origin', origin) // 允许携带哪个头访问我 res.setHeader('Access-Control-Allow-Headers', 'name') // 允许哪个方法访问我 res.setHeader('Access-Control-Allow-Methods', 'PUT') // 允许携带cookie res.setHeader('Access-Control-Allow-Credentials', true) // 预检的存活时间 res.setHeader('Access-Control-Max-Age', 6) // 允许返回的头 res.setHeader('Access-Control-Expose-Headers', 'name') if (req.method === 'OPTIONS') { res.end() // OPTIONS请求不做任何处理 } } next() }) app.put('/getData', function(req, res) { console.log(req.headers) res.setHeader('name', 'jw') //返回一个响应头,后台需设置 res.end('我不爱你') }) app.get('/getData', function(req, res) { console.log(req.headers) res.end('我不爱你') }) app.use(express.static(__dirname)) app.listen(4000)

        2.2.JSONP跨域

 Script不受浏览器同源策略的影响,所以通过 Script 便签可以进行跨域的请求:

  1. 首先前端先设置好回调函数,并将其作为 url 的参数。
  2. 服务端接收到请求后,通过该参数获得回调函数名,并将数据放在参数中将其返回
  3. 收到结果后因为是 script 标签,所以浏览器会当做是脚本进行运行,从而达到跨域获取数据的目的。
//后端逻辑 var url = require('url') var http = require('http') http.createServer(function (req, res) { var data = { name: "haha" }; var callback = url.parse(req.url,true).query.callback; //url.parse(req.url,true).query即{callback:jsonpCallback} ----------------获取函数名callback res.writeHead(200) res.end(`${callback}(${JSON.stringify(data)})`) }).listen(3000, '127.0.0.1') //服务端接收到请求后获取到回调函数名callback,将数据放在参数中将其返回,即返回callback({"name" : "haha"}) 函数调用 console.log('监听127.0.0.1:3000端口') //注意这里文字一定要引号包裹不然会报错 //注意终端提示:SyntaxError: Invalid or unexpected token 无效或意外的标记,出现这种情况一般是中文的标点符号或者漏写了符号导致的
 
   
   
   JSONP实现跨域 
    
    //web页面上调用js文件不收同源策略影响 
  

        2.3.nginx反向代理

实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。

使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

先下载nginx,然后将nginx目录下的nginx.conf修改如下:

// proxy服务器
server {
    listen       80;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }
}

最后通过命令行 nginx-s reload启动nginx

// index.html
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
// server.js var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { 'Set-Cookie': 'l=a;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/221069.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午6:59
下一篇 2026年3月17日 下午7:00


相关推荐

  • ASP NET MVC Web开发教程

    ASP NET MVC Web开发教程ASPNETMVCWeb开发教程使用ASPNETMVC和C#快速学习Web开发。从绝对基础到忍者!像专业人士一样学习C#和MVC课程英文名:CompleteASPNETMVCWebDevelopment-NewbietoNinja!此视频教程共4.0小时,中英双语字幕,画质清晰无水印,源码附件全百度网盘地址:https://pan.baidu.com/s/1tarxUTa-F0KOPeXXmocLLg?pwd=7evf课程介绍:https://www.aihor

    2022年7月22日
    12
  • slab下kmalloc内核函数实现

    slab下kmalloc内核函数实现文章目录 kmalloc 的整体实现获取高速缓存高速缓存获取 index 总结 https blog csdn net article details 在这篇文章中 我们介绍了伙伴算法 slab 机制和常见的内存管理函数 接下来 我们看看 kmalloc 内核函数的具体实现 kmalloc 分配连续的物理地址 用于小内存分配 get free page 分配连续的物理地址 用于整页分配 在 slab 机制下 还有 slob slub kmalloc 函数是基于 s

    2026年3月17日
    2
  • UVa 10763 – Foreign Exchange

    UVa 10763 – Foreign Exchange

    2021年9月2日
    50
  • [CF1105D]Kilani and the Game

    [CF1105D]Kilani and the Game

    2021年6月29日
    90
  • perl对中文的支持

    perl对中文的支持

    2021年7月29日
    76
  • armv6、armv7、armv7s、arm64 与开发静态库(.a)

    armv6、armv7、armv7s、arm64 与开发静态库(.a)声明:本帖系列均为在转载和摘抄的基础上进行补充。若转载请备注原文出处。/** 第一部分 初步认识*/ARM是微处理器行业的一家知名企业,arm处理器以体积小和高性能的优势在嵌入式设备中广泛使用,它的性能在同等功耗产品中也很出色,几乎所有手机都是使用它的。Armv6、armv7、armv7s、arm64都是arm处理器的指令集,所有指令集原则上都是向下兼容

    2022年6月29日
    65

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号