同源策略与CORS(跨源资源共享)以及django项目支持CORS

一、同源策略/SOP(Same origin policy)

1.1 源(origin)的定义

以下三个部分共同构成了一个源:

  • 协议:如http、https、ftp等;

  • 域名:如www.baidu.comwww.google.com等;

  • 端口:如443、80等。

1.2 同源的含义

如果两个 URL 的源完全相同的话,则这两个 URL 是同源

举例来说, http://store.company.com/dir/page.html 与下面的 URL 比较:

URL结果原因
http://store.company.com/dir2/other.html同源只有路径不同
http://store.company.com/dir/inner/another.html同源只有路径不同
https://store.company.com/secure.html失败协议不同
http://store.company.com:81/dir/etc.html失败端口不同 ( http:// 默认端口是80)
http://news.company.com/dir/other.html失败主机不同

1.3 同源策略

同源策略是一个重要的安全策略,它是浏览器最核心最基本的安全功能。它用于限制非同源的站点之间如何进行数据交互,极大程度上防止了如CSRF、XSS等网络攻击。

具体的限制措施如下:

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

二、CORS(跨源资源共享)

由于浏览器的同源策略,浏览器不能向不同源的URL发送AJAX请求,但有时候还就需要这样做。这个问题有几种解决方案,但最终极的解决方案是CORS。

CORS是一个W3C标准,全称是“跨源资源共享”(Cross-origin resource sharing)。它允许浏览器不同源的URL发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS是基于HTTP头的,它新增了一组 HTTP 首部字段,允许服务器声明哪些源站可以通过浏览器访问哪些资源。

2.1 预检请求

对于某些请求,**浏览器必须首先使用 OPTIONS方法发起一个预检请求,从而获知服务端是否允许该跨源请求。**服务器确认允许之后,才发起实际的 HTTP 请求。

2.2 请求分类

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

简单请求不会触发CORS预检请求,而非简单请求则必须发送预检请求。

满足以下条件的,属于简单请求:

  • 请求方法是以下三种之一:
    • HEAD
    • GET
    • POST
  • HTTP的头信息不超出以下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain
  • 请求中的任意 XMLHttpRequest对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload属性访问。
  • 请求中没有使用 ReadableStream对象。

而凡是不同时满足上面的任何一个条件,就属于非简单请求。

2.3 简单请求

对于简单请求,浏览器在头信息之中,增加一个Origin字段,然后直接发出CORS请求。请求报文的例子如下:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

请求首部字段Origin 表明该请求来源于 http://foo.example

如果该源服务器的允许范围之内,那么服务器就会返回一个携带了Access-Control-Allow-Origin头部信息的HTTP响应:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。

如果该源不在服务器的允许范围之内,那么服务器就会返回一个正常的HTTP响应。但浏览器发现响应没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。

2.4 非简单请求

浏览器发出CORS非简单请求,会在正式通信之前先发送预检请求。询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。

预检请求示例:

OPTIONS /resources/post-here/ HTTP/1.1
Host: qcloud.com
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://apigw.qcloud.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

Access-Control-Request-Method告诉服务器发的请求是POST请求,Access-Control-Request-Headers通知自己带有X-PINGOTHER自定义header。

响应报文示例:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://apigw.qcloud.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

Access-Control-Allow-Origin与前面类似,Access-Control-Allow-Methods这里说明支持POST/GET/OPTIONS方法,Access-Control-Allow-Headers这里说明允许X-PINGOTHER自定义header,Access-Control-Max-Age用来指定本次预检请求的有效时间,86400是24小时也就是一天。


一旦服务器通过了”预检”请求,在Access-Control-Max-Age指定的时间内,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

三、使Django项目支持CORS

3.1 自定义中间件

具体实现这里就不讲了,大体思路就是根据请求报文判断请求类型,然后再去做响应的处理。

3.2 使用django-cors-headers

3.2.1 安装

  1. 使用pip安装:

    pip install django-cors-headers
    
  2. 注册app:

    INSTALLED_APPS = [
        ...,
        "corsheaders",
        ...,
    ]
    
  3. 添加到中间件:

    MIDDLEWARE = [
        ...,
        "corsheaders.middleware.CorsMiddleware",
        "django.middleware.common.CommonMiddleware",
        ...,
    ]
    

    CorsMiddleware应该放在尽可能高的位置,特别是在任何能够生成响应的中间件之前,比如Django的CommonMiddleware或Whitenoise的WhiteNoiseMiddleware。如果没有,它将不能向这些响应添加CORS头。

3.2.2 配置

在Django设置中配置中间件的行为,以下三种配置的至少配置一种:

  • CORS_ALLOWED_ORIGINS:允许CORS的源。

    CORS_ALLOWED_ORIGINS = [
        "https://example.com",
        "https://sub.example.com",
        "http://localhost:8080",
        "http://127.0.0.1:9000",
    ]
    
  • CORS_ALLOWED_ORIGIN_REGEXES:与上面的配置项类似,只不过支持正则表达式。

    CORS_ALLOWED_ORIGIN_REGEXES = [
        r"^https://\w+\.example\.com$",
    ]
    
  • CORS_ALLOW_ALL_ORIGINS:是否允许所有的源进行CSOR请求,默认为False。

还有一些其他的配置:

  • CORS_ALLOW_CREDENTIALS:如果为True,则允许在跨源的HTTP请求中包含cookie。默认值为False。

  • CORS_ALLOW_METHODS:允许跨源请求的请求方法。

    CORS_ALLOW_METHODS = [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT",
    ]
    

更详细的配置参考官方文档:传送门

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花_城

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值