跨域问题讨论

文章讲述了跨域的定义及其带来的安全隐患,特别是CSRF攻击。介绍了SOP策略的局限性以及不受限的和受限的资源列表。重点讲解了CORS机制如何确保跨域访问的安全,并提到使用CSRFToken作为额外的防范手段。同时,反向代理也被提及作为一种回避跨域问题的方法。
摘要由CSDN通过智能技术生成

问题

跨域定义

当一个请求url的协议、域名、端口三者之间任意一个与当前页面地址不同即为跨域

跨域的安全隐患(CSRF攻击)

在这里插入图片描述

也就是说,一旦允许跨域,意味着允许恶意网站随意攻击可信网站,带来安全风险。

这里面有一个前提:

用户必须先登录可信站点A才行(登录cookie会保存在客户本地)。

解决方案

SOP策略

SOP:same-origin policy,同源策略

现代浏览器默认遵循同源策略,即网站A的请求不能去访问网站B。

但,<img>、<iframe>、<script>、<link>、<video>、<audio>等标签不受同源策略约束,这些标签可以通过src属性请求到其他服务器上的数据;如<img>的src(获取图片),<script>的src(获取javascript),iframe更是把不同网站的前端页面无缝衔接起来的常用技巧。

所以,即使在浏览器支持SOP的情况下,前例中的恶意网站仍可以构造例如img src这样的恶意代码,绕过浏览器的SOP规则,访问正常网站A。

不受SOP限制的资源清单:
脚本文件 js
图片资源
样式资源css
iframe展示其他的的资源
a链接访问其他资源
多媒体等资源
form表单提交

受SOP限制的资源清单:
跨域的XHR请求
iframe可以访问iframe整体,不能访问内容
cookie的限制,使用CORS需要withCredentials=true才可以带上cookie,否则cookie都没法带。

CORS机制

SOP原则可防范跨域,但如果确有需要跨域,如何安全的进行呢?

W3C推荐了一种跨域的访问验证的机制,即CORS(Cross-Origin Resource Sharing 跨源资源共享)。

这种机制让Web应用服务器能支持跨域访问,减轻跨域请求的风险。 CORS验证机制需要客户端和服务端协同处理。

CORS原理具体可参考这里

写得非常详细,我们可以概况为:为支持CORS,浏览器为我们的跨站XHR请求自动加了一个额外的请求头Origin,记录原始站点O,询问后台是否允许跨域(复杂请求会先自动通过OPTIONS请求专门询问一次,简单请求就没有提前的OPTIONS询问了),后台在响应头里返回关键字段Access-Control-Allow-Origin,给出允许跨域的网址P。浏览器将P跟O匹配,匹配上了,就可以继续访问,匹配不上就报错。若响应头里没有Access-Control-Allow-Origin字段,说明后台就不接受跨域XHR请求,浏览器会报:

No 'Access-Control-Allow-Origin' header is present on the requested resource

观察下来,对于简单请求(例如GET),实际运行中,浏览器其实是调了后台服务的,只不过后台服务没返回Access-Control-Allow-Origin,浏览器直接把结果扔了,对调用者报了这个错。对于POST请求,因为我们一般都是传的json,算复杂请求,会自动触发OPTIONS询问,就不会真正调用到后台服务的业务处理里了。

顺带说一下,域内请求,就没有Origin字段了,后台去拿,也只能拿到null或空。另外,因为CORS安全约束,请求头里的Origin字段是浏览器自动设置的,程序是无法强改的(能改的话,CORS机制就形同虚设了)。

由于浏览器侧是自动处理的,我们主要看后台的代码处理,以flask为例 :

@app.route('/repair_plans/page/<int:page_size>/<int:cur_page>')
def query_data(page_size, cur_page):
    app.logger.info('size:%d, cur_page:%d' % (page_size, cur_page))
    res =  jsonify(
        pageVO = {'totalRows':1},
        result = []
    )

    res.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin')
    res.headers['Access-Control-Allow-Methods'] = 'GET'
    res.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'
    return res

逻辑很简单,把Access-Control-Allow-Origin等几个CORS相关的响应头补上去即可。这里说明一下,Access-Control-Allow-Origin可以指定是原始站点O,也可以是一个预置的合法站点,一般不建议用星号通配符。若该字段设置为None或空,前端的跨域XHR请求就会报错:

The 'Access-Control-Allow-Origin' header contains the invalid value 'None'.

csrf token

准确的讲,CORS是跨域访问的例外规范,而非跨域攻击的防范。

跨域攻击的防范,首先还是浏览器的SOP策略,但前面说了,SOP有例外,像img src、链接、表单提交等都可以绕过SOP,浏览器不会报错,且这些做法的请求头里都没有Origin字段,后台只能通过检查referer字段来防范。但referer字段是可以在浏览器里配置不发送的(出于隐私保护的考虑)。最后,即便浏览器支持,你也不知道这个浏览器是否因安全漏洞被攻陷,导致referer可被篡改,所以还需要一个更强的防范措施,这就是csrf token。

用户登录后,随机生成csrf_token,用户在做核心操作表单提交(POST)时必须在请求头里携带csrf_token,并且在服务端校验csrf_token的合法性。由于恶意站点是无法构造CSRF Token的(只有登陆可信站点才能获取到,且CSRF Token一般不放在cookie中),因此CSRF Token是目前最成熟、使用最广泛的方法。
这是SO上的一段说明,印证了本节的说法:

Origin vs Referer vs CSRF token
Most likely, the reason OWASP recommends also using a CSRF token, is that at the time when this recommendation was made - a significant portion of browsers did not yet support the Origin header. This is no longer the case, but people are chimpanzees.

In order to preserve privacy, any browser request can decide to omit the Referer header. So it is probably best to only check the Origin header. (In case you want to allow for users to preserve their privacy)

The Origin header is null in some cases. Note that all of these requests are GET requests, which means they should not have any side effects.

As long as you make sure the malicious website sending the requests with your browser cannot read the responses, you should be fine. This can be ensured using proper CORS headers. (Do not use Access-Control-Allow-Origin: *!)

To prevent "click-jacking", set the header X-Frame-Options: DENY. This will tell your browser that it is not allowed to display any part of your website in an iframe.

大意是说,referer、Origin不是万无一失的,最好补充上csrf token。

反向代理

参见这里

这里把对网站A和B的访问都集中到nginx处,天然回避了跨域(比如,A访问B)的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值