CORS跨域资源共享

定义

CORS(Cross-Origin Resource Sharing)是一种机制,它使用额外的 HTTP 头来告诉浏览器允许一个网页从另一个域(不同于该网页所在的域)请求资源。这样可以在服务器和客户端之间进行安全的跨域通信

名词解释

Origin(域)

Origin = 协议 + 域名 + 端口

域由三个部分组成【协议(Protocol)、主机名(Host/Domain Name)、端口号(Port Number)】只有当这三个部分完全相同的时候,两个 URL 才被认为是同一个“源”或“域”。例如:

跨域请求

一个网页通过 JavaScript 发起的请求目标是不同于该网页所在的源(协议、域名、端口)

例如我在百度首页页面去访问我本地的web服务

抓包可以看到浏览器检测到了跨域请求origin头被浏览器加到了请求中,我的web服务是允许这个origin的,所以成功收到了我的服务的响应,状态码为200

同源策略

同源策略(Same-Origin Policy, SOP)是浏览器的一种安全机制,用于防止恶意网站通过脚本对其他网站的内容进行访问。“同源”,是指协议、域名和端口都相同

CORS 工作流程

CORS 通过在 HTTP(s) 请求和响应中使用特定的头部字段来实现跨域资源共享,CORS 分为两种类型的请求处理方式:简单请求和预检请求

  • 简单请求:对于某些简单的 HTTP 请求(如GET、POST请求且不包含自定义头部),浏览器会直接发送请求,并在响应中检查 CORS 头部。

  • 预检请求:对于复杂请求(如使用PUT、DELETE方法,或包含自定义头部),浏览器会首先发送一个OPTIONS请求,称为预检请求(Preflight Request),以确定服务器是否允许实际请求。

简单请求

  • 简单请求是指满足以下条件的 HTTP 请求:

1、使用GET、POST、HEAD方法

2、请求头部仅包含以下字段:Accept、Accept-Language、Content-Language、Content-Type(且值为application/x-www-form-urlencoded、multipart/form-data或text/plain)

  • 对于简单请求,浏览器会直接发送请求并在响应中检查以下 CORS 头部:

1、Access-Control-Allow-Origin:指示允许访问资源的源。

2、Access-Control-Allow-Credentials:指示是否允许发送凭据(如Cookies)。

3、Access-Control-Expose-Headers:指示哪些头部可以作为响应的一部分被访问

  • 例如

GET /api/data HTTP/1.1   
Host: www.yuanjava.com   
Origin: https://yuanjava.com   
HTTP/1.1 200 OK   
Access-Control-Allow-Origin: https://yuanjava.com   
Content-Type: application/json      
{"message": "Hello, CORS!"}   

预检请求

  • 对于复杂请求,浏览器会首先发送一个 OPTIONS 请求,包含以下头部字段:

Origin:指示请求的源。

Access-Control-Request-Method:指示实际请求将使用的方法。

Access-Control-Request-Headers:指示实际请求将包含的自定义头部。

  • 服务器收到预检请求后,会返回一个响应,包含以下头部字段以指示是否允许请求:

Access-Control-Allow-Origin:表明允许访问资源的源,可以是具体的源或通配符 *

Access-Control-Allow-Methods:表明允许的方法,如 GET, POST, PUT, DELETE

Access-Control-Allow-Headers:表明允许的自定义头部

Access-Control-Allow-Credentials:表明是否允许发送凭据(如 Cookies)

Access-Control-Expose-Headers:表明哪些头部可以作为响应的一部分被访问

Access-Control-Max-Age:表明预检请求的结果可以被缓存的时间,单位是秒

  • 如果预检请求通过,浏览器会继续发送实际请求

  • 例如

OPTIONS /api/data HTTP/1.1   
Host: api.yuanjava.com   
Origin: https://yuanjava.com   
Access-Control-Request-Method: PUT   
Access-Control-Request-Headers: Content-Type   
HTTP/1.1 204 No Content   
Access-Control-Allow-Origin: https://yuanjava.com   
Access-Control-Allow-Methods: GET, POST, PUT   
Access-Control-Allow-Headers: Content-Type   
Access-Control-Allow-Credentials: true   
Access-Control-Max-Age: 3600   
PUT /api/data HTTP/1.1   
Host: api.yuanjava.com   
Origin: https://yuanjava.com   
Content-Type: application/json      

{"data": "example"}   
HTTP/1.1 200 OK   
Access-Control-Allow-Origin: https://yuanjava.com   
Content-Type: application/json      

{"message": "Data updated"}   

CORS测试

Access-Control-Allow-Origin测试

web服务,用python起了一个web服务,配置了些CORS规则且支持处理预检请求

from flask import Flask, request, jsonify
from flask_cors import CORS

app = Flask(__name__)

# 配置 CORS 策略
CORS(app, resources={
    r"/data/*": {
        "origins": ["https://www.baidu.com"],  # 只允许来自特定源的请求
        "methods": ["GET", "POST", "DELETE", "OPTIONS"],
        "allow_headers": ["Content-Type"],
        "supports_credentials": False,
        "max_age": 86400
    }
})

@app.route('/data', methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])
def handle_data():
    origin = request.headers.get('Origin')

    # 检查 Origin 是否在允许列表中
    allowed_origins = ["https://www.baidu.com"]

    if origin not in allowed_origins:
        response = jsonify({"status": "Access denied", "reason": "Source not allowed"})
        return response, 403

    # 处理 OPTIONS 请求
    if request.method == 'OPTIONS':
        response = app.make_default_options_response()
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
        return response

    # 模拟返回一些数据
    data = {"message": "Data successfully retrieved"}

    response = jsonify(data)
    response.headers['Access-Control-Allow-Origin'] = origin  # 设置响应头部为允许的 Origin
    return response

if __name__ == '__main__':
    app.run(port=5006)  # 在端口 5006 上运行
burp测试

origin头为https://www.baidu.com,正常收到服务器响应,状态码200

origin头非https://www.baidu.com,例如端口有变,协议有变,域名有变均无法访问服务

浏览器访问测试

在百度首页发送请求访问我的服务,浏览器识别到跨域,自动加上origin头,因为我的服务上的cors规则允许的origin头为https://www.baiud.com,刚好匹配即正常收到服务器响应

在csdn首页发送请求访问我的服务,可以看到被阻断了,无法访问,因为origin没在服务的允许范围内

Access-Control-Allow-Methods测试

用put方式发送请求,预检请求可以看到服务不允许PUT类型访问,所以访问报错响应405 METHOD NOT ALLOWED

CORS(Cross-Origin Resource Sharing)是一种机制,用于允许在一个名下的Web应用程序访问另一个名下的资源。默认情况下,浏览器会限制请求,以防止恶意的行为。但是,使用CORS,服务器可以通过在响应头中包含特定的标头来指示浏览器允许请求。 要启用CORS,服务器需要在响应头中包含一些特定的标头字段。其中最常见的是"Access-Control-Allow-Origin",它指定了允许访问资源的源。服务器可以设置这个字段为特定的名,或者使用通配符"*"来表示允许来自任何的请求。 此外,还有其他一些相关的标头字段,例如"Access-Control-Allow-Methods"用于指定允许的HTTP方法,"Access-Control-Allow-Headers"用于指定允许的请求头,以及"Access-Control-Allow-Credentials"用于指示是否允许发送身份验证凭据。 在客户端发起请求时,浏览器会首先发送一个预检请求(OPTIONS请求),以获取服务器是否支持请求。服务器收到预检请求后,会返回相应的响应头以及状态码,如果满足要求,则浏览器会发送实际的请求。 需要注意的是,CORS仅适用于浏览器发起的请求,对于直接通过HTTP工具发送的请求,不会受到CORS的限制。此外,CORS仅在符合同源策略的情况下才会生效,即协议、名和端口号必须完全相同。 希望这能解答你关于CORS资源共享的问题!如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值