IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 再谈同源策略及跨域 -> 正文阅读

[网络协议]再谈同源策略及跨域

同源策略

浏览器的同源策略 (Same Origin Policy)

image.png

同源策略是网站安全的基石,https://a.com只能存取自己网站的资源,不允许网站https://b.com来存取。
目的是为了保证用户信息的安全,防止恶意的网站窃取数据。

判断

只要url当中的协议scheme、域名domain、端口port都一样,就会被视为就会被视为同源 (same-origin),
其他则是不同源。

image.png

http://domain-a.com → 不同源.scheme 不同
https://domain-a.com/mike → 同源
https://news.domain-a.com → 不同源.domain 不同
https://domain-a.com:81 → 不同源.port 不同
https://domain-b.com → 不同源.domain 不同

限制范围

1、在某些情況下跨来源是被允许的,比如跨来源嵌入。
script、link、img、iframe、video、audio、font-face等等。

2、如非同源,跨来源读取通常被禁止。

  • Cookie、LocalStorage 和 IndexDB 无法读取。
  • DOM 无法获得。
  • AJAX 请求不能发送。

Cookie的跨域

Cookie的同源策略

image.png

只要 domain 跟 Path 与Cookie 上的一样就会被视为同源。若经过一些设定才会判断 scheme 要是 http 或 https。

// 加了 Secure 会限定此 Cookie 只能以 https 传送
Set-Cookie: id=1234567; domain=hello.com; Secure

下面这样设置,domain为一级域名,二级域名和三级域名不用做任何设置,都可以读取这个Cookie

Set-Cookie: key=value; domain=.example.com; path=/

跨域携带Cookie

跨域请求如何携带cookie

withCredentials

**XMLHttpRequest.withCredentials **属性是一个Boolean类型,它指示了是否该使用类似cookies,authorization headers(头部授权)或者TLS客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用withCredentials属性是无效的。

设置Cookie

用同源的前端页面去请求接口
如果是非同源前端则需要带上withCredentials,才能够成功保存Cookie数据,
Cors配置Origin也不能设置为*了,跨域使用ctx.headers.origin

如果在发送来自其他域的XMLHttpRequest请求之前,未设置withCredentialstrue,那么就不能为它自己的域设置cookie值。而通过设置withCredentials为true获得的第三方cookies,将会依旧享受同源策略,因此不能被通过document.cookie或者从头部相应请求的脚本等访问。

设置**httpOnly: false**** document.cookie却可以访问**

不同域下的XmlHttpRequest响应,不论其Access-Control- header 设置什么值,都无法为它自身站点设置cookie值,除非它在请求之前将withCredentials设为true

image.png
同源请求

**Request Header**中有一条 **Cookie: user=forguo**,因为属于同源所以会自己携带上**Cookie**信息

查看浏览器 Application> Cookie可以看到Cookie信息已经存储成功
![image.png](https://img-blog.csdnimg.cn/img_convert/04ecb0dc3b304a430deb62d501b95fec.png#clientId=u4925323a-4f05-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=329&id=PMW5F&margin=[object Object]&name=image.png&originHeight=329&originWidth=1119&originalType=binary&ratio=1&rotation=0&showTitle=false&size=26640&status=done&style=none&taskId=ub2e348a9-b204-4838-a289-8efaaffd9df&title=&width=1119)

服务端设置Cookie

ctx.cookies.set("user", "forguo", {
    domain: '127.0.0.1',  // 写cookie所在的域名
    path: '/',       // 写cookie所在的路径
    maxAge: 10 * 60 * 1000, // cookie有效时长 10分钟
    expires: new Date('2022-03-15'),  // cookie失效时间
    httpOnly: true,  // 是否只用于http请求中获取
    overwrite: false  // 是否允许重写
});

此时,接口返回的Response Headers会设置Cookie

Set-Cookie: user=forguo; path=/; expires=Fri, 11 Mar 2022 06:21:27 GMT; domain=127.0.0.1; httponly

携带Cookie

1、前端添加withCredentials

在前端请求的时候设置request对象的属性withCredentialstrue

// axios添加withCredentials
axios({
    method: "get",
    withCredentials: true, // ++ 携带cookie数据
    url: "http://127.0.0.1:3009/user/info",
}).then((res) => {
    console.log(res);
});

2、服务端设置Access-Control-Allow-Origin

此时,我们从 http://127.0.0.1:3003/http://127.0.0.1:3009/user/info 去发起一个请求,发现报错
意思是需要设置header的Access-Control-Allow-Origin属性:

image.png

携带了Cookie,但是报错CORS error

image.png

这里对应的值,和前端同步,最好不要设置为(跨域设置Cookie会报错),可以使用*ctx.headers.origin

const cors = async (ctx, next) => {
    // 设置跨域
    ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
    // ctx.set('Access-Control-Allow-Headers', 'X-Auth-Token, Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    // ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    // 允许携带cookie
    // ctx.set('Access-Control-Allow-Credentials', 'true');
    if (ctx.method === 'OPTIONS') {
        ctx.body = 200;
    } else {
        const start = new Date();
        await next();
        const ms = new Date() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    }
};

如果是下面这个错误,就说明配置的Origin和当前前端所在Origin不是同一个
that is not equal to the supplied origin.

![image.png](https://img-blog.csdnimg.cn/img_convert/e3f33c957dc1598cdbfd8ab6fa53c42c.png#clientId=u31e4d5d9-f672-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=187&id=ua6ac0953&margin=[object Object]&name=image.png&originHeight=187&originWidth=613&originalType=binary&ratio=1&rotation=0&showTitle=false&size=26636&status=done&style=none&taskId=ua42ef69b-1950-4cdc-94e7-a12b4c3e785&title=&width=613)

3、服务端设置Access-Control-Allow-Credentials

重复1的请求,发现还是报错
意思是Access-Control-Allow-Credentials这个属性应该设置为true
当然如果前端没有设置withCredentials,是不会携带Cookie的,也不会有这个错误的
image.png

const cors = async (ctx, next) => {
    // 设置跨域
    ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);
    // ctx.set('Access-Control-Allow-Headers', 'X-Auth-Token, Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    // ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    // 允许携带cookie
    ctx.set('Access-Control-Allow-Credentials', 'true');
    if (ctx.method === 'OPTIONS') {
        ctx.body = 200;
    } else {
        const start = new Date();
        await next();
        const ms = new Date() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    }
};

再去发起1的请求,会发现请求成功,并且返回了cookie数据

image.png

接口处理是解析了Cookie内容,并返回

.get('/info',async ctx => {
    let user = {};
    if (ctx.headers.cookie) {
        // req.headers.cookie: user=forguo
        user = ctx.headers.cookie.split("=")[1];
    }
    ctx.body = {
        data: {
            user,
            cookie: ctx.headers.cookie,
        },
        code: 200,
        serverTime: Date.now(),
    };
})

Ajax跨域

同源政策规定,ajax请求只能发给同源的网址,否则就报错。

解决方案

  • JSONP
  • 服务器代理
  • CORS
  • WebSocket

Jsonp

实现一个简易jsonp:https://github.com/wforguo/daily-code/tree/master/cors

  • 优点:简单适用,老式浏览器全部支持,服务器改造非常小。
  • 缺点:只支持get请求。

基本思路是:向网页动态插入

web端代码

/**
 * @desc js原生实现jsonp
 */
function jsonpRequest () {
    // 创建一个script标签,并插入页面
    let script = document.createElement('script');

    // 获取到跨域资源后的回调
    window.handleFn = function (res) {
        // JSONP跨域成功返回的资源
        console.log(res);
        //代码执行后,删除插入的script标签
        document.getElementsByTagName('head')[0].removeChild(script);
    }
    let url = `http://127.0.0.1:3003/common/wechat/sdk?callback=handleFn`;
    script.setAttribute('src', url);
    // 将script标签插入到网页中
    document.getElementsByTagName('head')[0].appendChild(script);
}

jsonpRequest();

服务端代码

// koa2
router
.get('/jsonp',async ctx => {
    let method = ctx.request.method || 'GET';
    let params = {};
    if (method === 'GET') {
        params = ctx.request.query;
    }
    if (method === 'POST') {
        params = ctx.request.body;
    }
    try {
        if (params.callback) {
            // 返回结果
            let res = params.callback + '(' + JSON.stringify({
                data: {
                    now: Date.now(),
                },
                code: 200,
            }) + ')';
            // 需要注明Content-Type
            ctx.response.type = 'application/javascript;charset=utf-8';
            ctx.body = res;
        } else {
            ctx.response.type = 'application/json;charset=utf-8';
            ctx.body = {
                data: {
                    now: Date.now(),
                },
                code: 200,
            };
        }
    } catch (e) {
        console.log(e);
        throw e;
    }
})

使用代理

nginx代理

server {
  # 转发api到node服务
  location /api/ {
    proxy_pass http://127.0.0.1:3333/api/;
  }
}

node.js代理

// koa2
/* 代理配置 start */
const proxy = require('koa2-proxy-middleware'); //引入代理模块
const options = {
    targets: {
        // (.*) means anything
        '/api/(.*)': {
            target: 'http://test02.com/',
            changeOrigin: true,
        },
    }
}
app.use(
    proxy(options)
);

const bodyparser = require('koa-bodyparser')
app.use(bodyparser({
    enableTypes: ['json', 'form', 'text']
}))

/* 代理配置 end */

Cors

跨源资源分享(Cross-Origin Resource Sharing),通过相应的请求头与响应头来实现跨域资源访问。

参数

  • Access-Control-Allow-Origin

如果将Access-Control-Allow-Origin的值设置为*,则会接受所有域的请求。这时的客户端不需要任何配置即可进行跨域访问。

  • Access-Control-Allow-Credentials

Access-Control-Allow-Origin相配套的,还有一个叫Access-Control-Allow-Credentials的响应头,如果设置为true则表明服务器允许该请求内包含cookie信息。

同时,在客户端,还需要在ajax请求中设置withCredentials属性为true

// axios 拦截器
instance.interceptors.request.use((config) => {
    const token = localStorage.getItem('token');
    config.headers.common['Authorization'] = 'Bearer ' + token;
    config.withCredentials = true;
    return config;
}, err => {
    return Promise.reject(err);
});
  • Access-Control-Expose-Headers

  • Access-Control-Request-Method

配置

完整的cors配置

// koa2
const cors = async (ctx, next) => {
    // 设置跨域
    ctx.set('Access-Control-Allow-Origin', '*');
    ctx.set('Access-Control-Allow-Headers', 'X-Auth-Token, Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    ctx.set('Access-Control-Allow-Credentials', 'true');
    if (ctx.method === 'OPTIONS') {
        ctx.body = 200;
    } else {
        const start = new Date();
        await next();
        const ms = new Date() - start;
        console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
    }
};

WebSocket

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

复杂请求与简单请求?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 22:11:44  更:2022-03-13 22:11:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:22:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码