V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chinafengzhao
V2EX  ›  信息安全

CROS 同源问题的一些疑问

  •  
  •   chinafengzhao · 22 天前 · 2230 次点击

    最近在学习 CORS 同源策略问题,看到几个观点:

    1 、跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是响应结果被浏览器拦截了。 不仅仅是静态的资源。WebStorage 、Cookie 、IndexDB ,在浏览器层面上都是以域这一概念来划分管理的。 而且这个划分管理行为,就是在浏览器本地生效。和服务器、其他客户端没有直接关系。

    2 、当响应的是附带身份凭证的请求时,服务端必须明确 Access-Control-Allow-Origin 的值,而不能使用通配符。

    针对 1 ,比如说我做为可能有恶意脚本的黑客,不管你请求头带不带 origin ,我返回的 js 响应报文中,我始终带上 "Access-Control-Allow-Origin: *"这个响应头啊。 这样我的恶意 js 不就可以被浏览器解释并执行了?

    针对 2 ,这个服务端必须是为什么要必须明确呢?如果不明确会怎么样呢? CORS 做为一个浏览器对资源请求的约束,它咋知道我的请求带不带身份呢?

    请教各位大佬赐教一下

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Guides/CORS

    https://zhuanlan.zhihu.com/p/38972475

    26 条回复    2025-08-22 12:40:22 +08:00
    lululau
        1
    lululau  
       22 天前
    我理解所谓「同源策略」是用来防止 CSRF 的而不是 XSS 的吧
    FlyaiF
        2
    FlyaiF  
    PRO
       22 天前
    应该是为了防止浏览器里边进行一些假冒的网站,引导用户做一些用户意料外的操作吧
    hurrytospring
        3
    hurrytospring  
       22 天前   ❤️ 2
    1. 对,但是需要理解安全机制防的是什么,cors 机制中,防范的是跨站脚本攻击,比如在 A 网站中,发起一个对你服务( B )的请求,这个时候就可以携带上 B 的 cookie ,然后在请求中读 B 身份的内容。
    至于你说的场景
    1.1. 是黑客劫持了响应,然后注入恶意脚本,其实这个时候没有那么麻烦,黑客可以直接劫持 A 的请求。
    1.2. 这个场景一般来说是依赖 https 或者更底层的协议来保护,跟 cors 没有关系
    2. 身份是一个统一的认证头,key 为 authorization ,如果你就是不用这个 key ,自己设计一个,你就自己越过了这个安全机制,你的服务你自己负责。
    2.1 allow:*本质上是一种宽松校验机制,就是如果你认为你这个接口信息不重要,可以让别的站随便拿,你可以定义为*。但是当有这个 header 时,浏览器认为,这不是一个宽松的接口,是含有认证信息的敏感接口,应该采用更严格的校验机制,所以不让你用宽松的配置。
    2.2 当然,你可以觉得浏览器说得不对,你换一个认证的 header key ,这个时候浏览器也不对这个事情负责,你可以继续 allow:* ,属于你自己越过安全机制,自己负责
    Y25tIGxpdmlk
        4
    Y25tIGxpdmlk  
       22 天前
    这好比就是正规浏览器遵守的一个保护用户的规则而已吧。

    比如有支付宝和微信 2 个网站,如果你用浏览器访问支付宝网站,支付宝如果很坏,里面嵌入了微信的页面。由于微信页面的跨域限制,支付宝页面是不能获取到他嵌入页面的相关数据的,比如 cookie 之类的。虽然对浏览器来说,2 个网站的数据他都有,但是浏览器会遵守一个约定,微信的页面说不能把内容让支付宝看,那他就会隔离 2 个网站。

    相应的,如果微信的页面返回里,允许了支付宝,那他的数据就会被共享给支付宝。说白了还是要看浏览器是不是正规,是不是遵守跨域限制。当然你也可以自己魔改一个浏览器或者客户端,直接不遵守跨域限制。
    Y25tIGxpdmlk
        5
    Y25tIGxpdmlk  
       22 天前
    其实你的这类问题,问 ai 是非常好用的,你各种不理解,可以一点点的问他,他会给你讲的非常到位
    bronyakaka
        6
    bronyakaka  
       22 天前
    一个和 cors 无关,自己信任了外部输入并执行,毕竟传过来的本来只是 js 字符串而已;第二个是 csrf
    chinafengzhao
        7
    chinafengzhao  
    OP
       22 天前
    问过了,并不到位,甚至会乱回答。
    cppc
        8
    cppc  
       22 天前
    1 简单请求是浏览器直接发出,收到服务器响应后拦截

    2 非简单请求是先发预检请求,检查服务端响应头,然后根据规则再发实际请求(也就是说可能不会发出真实请求)
    AoEiuV020JP
        9
    AoEiuV020JP  
       22 天前
    cros 是保护用户自己的,入户用户自己是黑客不需要保护,cros 没用的,
    比如你作为用户可以安装一个插件“Allow CORS”,就能绕过 cors 的限制,我有时候用一些 web app 会这样,等于允许这个 web app 爬取其他网站的数据,

    如果用户不是黑客的话,中间人是靠 https 防范的,
    wangtian2020
        10
    wangtian2020  
       22 天前
    跨域是后端问题,后端问题
    禁止是浏览器出于安全,浏览器方面自作主张禁止的,默认假设你的 URL 是对的,如果 URL 不带跨域头那就不让页面收到信息
    wangtian2020
        11
    wangtian2020  
       22 天前
    例如,假如没有跨域限制,那我是不是可以做个跟支 F 宝完全一样的页面,只加一行代码把用户名密码发来
    那用户一看页面长的一样,页面行为也一样,不知不觉中就被盗了
    seekafter
        12
    seekafter  
       22 天前
    1. 是对的吗? 我理解的是浏览器做出的跨域限制. 因为同样的跨域请求, 浏览器提示 cors, api 工具就会成功
    2. 如果携带 cookie, 但设置"Access-Control-Allow-Origin: *", 你的 cookie 会自动被浏览器丢弃.
    另外如果你有自定义请求头, 还需要设置响应头为 Access-Control-Allow-Headers: cookie,自定义请求头 1, 头 2... 这个的设置要和你的请求头完全一致
    另外前端发请求还需要设置一个 inc 开头的属性. 等我博客启动了发你文章参考下
    GeruzoniAnsasu
        13
    GeruzoniAnsasu  
       22 天前
    A 域数据被 B 读,你要保护数据,请问是在 A 上设防火墙还是在 B 上?

    B 是发起 CORS 请求的站点,现在你理解了不?

    如果 A 域数据很敏感,你必然要开个白名单只允许特定 B 来读。除了这个白名单外,你可能希望 A 和 B 上都有一些过滤和拦截,那么浏览器就是 B 上的额外防护层。



    你从服务端该怎么响应请求的角度出发会容易理解得多,这也是为什么 CORS 明明只是个很简单的机制但为啥这么多前端一直迷迷糊糊的原因。
    fuzzsh
        14
    fuzzsh  
       22 天前 via Android
    OWASP 记录了大部分攻击手段和防护措施,可以看下他们的文档
    irisdev
        15
    irisdev  
       22 天前
    楼主这算是典型初学者的困惑,很多技术在不知道其背景之前总是会产生类似的疑问,其实大多数技术也只是某些场景好用,很多问题是没办法解决的,或者要在可用性、易用性、通用性和绝对安全之间作取舍
    fruitmonster
        16
    fruitmonster  
       22 天前
    V2 不知道为什么这么喜欢讨论跨域请求呢? /t/1056504 /t/1056793
    chinafengzhao
        17
    chinafengzhao  
    OP
       22 天前
    @seekafter 可以出一篇文章详解一下,等你大作。大家都在说跨域是浏览器行为, 这个我的理解是这样的,浏览器是个公共应用,用户打开浏览器可以访问各种各样的域名各种各样的网站。 网站会在客户端存各种各样的数据(比如用户身份登录态(抱歉这是我自己造的一个词),字体偏好等等(比如通过 session,cookie,webstorage 等),可以理解这是针对域名来对这些数据分开隔离的),所谓大家都在说,不允许带 cookie 啥的。 但是忽略了我的原始问题,不同网站的凭证可能是不同方式实现的,是业务自己私密的实现。这个也不属于标准或协议层面。


    **当响应的是附带身份凭证的请求时,服务端必须明确 Access-Control-Allow-Origin 的值,而不能使用通配符“*”。**

    协议或者说浏览器要求带这个头部之类的,他怎么判断这个是不是普通请求呢?有些请求里面有 cookie 不代表这是带凭证吧。
    @GeruzoniAnsasu
    unco020511
        18
    unco020511  
       22 天前
    1 的前提是你主动同意黑客这么干,或者说你就是黑客. 比如你主动在电脑中设置代理,并主动安装根证书到电脑,这样就你的 proxy 就可以随意修改 https 的请求和响应. 更进一步,你直接将你的电脑权限交给黑客.所以 1 已经超出了浏览器同源政策的范畴了
    2 的话你可以理解是一个额外安全要求,附带身份凭证会认为是敏感信息,所以有一个额外的安全规定.
    不过现在用户凭证很多都不用 cookie 之类的,你想放到哪都可以,比如额外搞个 header 附带 token.
    浏览器是一个 httpClicent,当然知道你发送的请求细节,包括 https 的握手加密等细节都是浏览器去实现的,它自然知道,具体到开发中,就是设置 withCredentials 的值,你设置为 true 就认为你带了
    chinafengzhao
        19
    chinafengzhao  
    OP
       22 天前
    以 MDN 为例,站点 https://foo.example 的网页应用想要访问 https://bar.other 的资源。

    如果 https://bar.other 的资源持有者想限制他的资源只能通过 https://foo.example 来访问(也就是说,非 https://foo.example 域无法通过跨源访问访问到该资源)

    那我做为 bar.other 来说,我可能有两类资源,一类是静态的什么 js 啥的,第二类是 api 接口业务数据啥的

    我想保护我自己。 所谓我可能要在一些有认证态(抱歉这是我造的词,不同网站可能不一样)的 http web api 加上响应头限制。 "Access-Control-Allow-Origin: https://foo.example:" 表示只能是 Origin 为 foo 的请求才能接收。 关键是这个响应已经发出去了啊, 我的保护意义何在呢?


    所以如果我设置失误了,对于带 cookie 或者说认证状态的请求,我在响应头 "Access-Control-Allow-Origin: *"设置为这样,浏览器反而自动给我加了个保护,响应虽然发出去了, 在浏览器不解析这个响应报文数据。 ? 所以这是君子协定,靠浏览器的机制保护来约束?

    可能这些才是我的疑惑,这些头部约束的目的和要解决的问题其实我是明白的,我其实想问它的控制机制和限制,


    MDN 这一系列不能,只是为了安全考虑,如果我设置了会怎么样他没说,并且还是那句话,不同的网站,带身份凭证的请求各有不同,做为这种跨域约束协定,或者说我用某个头部做为认证,然后不小心设置了 Access-Control-Allow-Origin: * , 客户端怎么判断请求是否带身份凭证呢?怎么判断这个*应该不被接收呢?


    ```

    在响应附带身份凭证的请求时:

    服务器不能将 Access-Control-Allow-Origin 的值设为通配符(*),而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com
    服务器不能将 Access-Control-Allow-Headers 的值设为通配符(*),而应将其设置为特定标头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
    服务器不能将 Access-Control-Allow-Methods 的值设为通配符(*),而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET
    服务器不能将 Access-Control-Expose-Headers 的值设为通配符(*),而应将其设置为特定标头名称的列表,如:Access-Control-Expose-Headers: Content-Encoding, Kuma-Revision
    对于附带身份凭证的请求(通常是 Cookie ),

    这是因为请求的标头中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 https://example.com ,则请求将成功执行。

    另外,响应标头中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。
    ```


    @GeruzoniAnsasu
    @GeruzoniAnsasu
    chinafengzhao
        20
    chinafengzhao  
    OP
       22 天前
    @unco020511 其实第一个情况,要考虑到类似 jscdn 这种网站到期了被抢注了,这种域名被篡改了之类的,我做为黑客不一定要中间人攻击请求报文或响应报文,我可能攻击了类似 CDN 这种。 比如说我攻破大家都在用的 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> 假设这是我的恶意脚本,在这脚本里面去请求我的网站呢。
    chinafengzhao
        21
    chinafengzhao  
    OP
       22 天前
    @unco020511 是的,你这个第二点说的很对,用户凭证这个东西不是标准,每个网站实现都不一样,所以我才对这个 MDN 里面关于用户凭证对 Access-Control- 各种头部的限制和要求不太理解。 有点疑惑。
    dorothyREN
        22
    dorothyREN  
       22 天前
    简单请求没有跨域的问题吧
    GeruzoniAnsasu
        23
    GeruzoniAnsasu  
       22 天前
    @chinafengzhao

    那你继续想想为什么会要有预检请求呢? 你已经接近理解了:
    https://github.com/amandakelake/blog/issues/62

    (随收一搜)
    UnluckyNinja
        24
    UnluckyNinja  
       22 天前
    假设跨域情景下的三个角色:用户(以及使用的浏览器),用户访问的网站 A ,网站 A 请求的网站 B 。
    首先要明确,跨域规则究竟是在防谁,是为了解决什么问题?
    用户访问网站 A ,或者用户访问网站 B ,网站与自身的互动都是同源的,被浏览器信任。
    用户访问网站 A 时与网站 B 产生互动,用户可能并不知道会涉及网站 B ,网站 B 也不能信任来自其它前端的不可靠输入,这样的互动是浏览器所要阻止的。
    所以,跨域规则是在防当前访问的网站 A 的恶意操作,保护用户与网站 B 之间的数据安全。
    如果网站 B 允许网站 A 的跨域请求,那么实际上跨域保护的作用已经结束了。

    再来看第一个问题,
    > “我做为可能有恶意脚本的黑客……我的恶意 js……”
    这里假定了网站 B 是恶意方,用户访问的网站 A 是正常的,但如果网站 A 都已经请求了恶意 js ,那网站 A 还是清白的吗?
    OP 在 20L 举了一个 CDN 投毒攻击的例子,但你首先要想到,在 CDN 投毒之前,这一切是正常运作的,网站 A 请求了网站 B 的资源,网站 B 允许网站 A 的跨域请求。
    后来其中某一方背叛了信任,虽然是不同源,但这根本不是跨域规则所要解决的问题,也就是需要禁止的跨域资源访问(非法请求访问合法资源),这直接就相当于是注入代码了。

    第二个问题,
    > “它咋知道我的请求带不带身份呢”
    你没写过附带身份凭证的前端请求?你不明确附带身份凭证,那浏览器就不会发送附带身份凭证的请求。凭证是由浏览器管理的,你无法在前端代码中修改跨域请求附带的凭证 https://fetch.spec.whatwg.org/#forbidden-request-header
    > “这个服务端必须是为什么要必须明确呢?如果不明确会怎么样呢? ”
    同样地,在跨域的语境下,你要搞清楚哪方是攻击方,哪方是受保护方(响应端、用户是被保护方,请求端是潜在的攻击方)。
    不明确就说明后端根本没有考虑到可能有来自不明源的攻击,既然不遵循浏览器的安全规则,浏览器就当你是需要被保护的对象,禁止一切风险行为。
    restkhz
        25
    restkhz  
       21 天前
    我不得不说,很多人理解就错了。CORS 出发点不是“为了安全”,而是为了灵活。

    很多人说的其实是 SOP ,同源策略。说白了就是分隔不同站点的 cookie ,认证 header ,资源等。
    而后又发现其实有时候我们也是需要跨域访问的,比如你前后段分离。但是因为 SOP ,很多事情都做不了。

    所以要打一个补丁,但是你总不能破坏 SOP 吧?所以搞了这一堆机制。存在部分安全限制的灵活。
    很多人的困惑就是因为直接看了 CORS ,就觉得这莫名其妙。所以楼主你还是从 SOP 看起吧。


    而且人们普遍对 web 攻击理解是有问题的。

    比如 3 楼,说的“跨站脚本攻击”,实际上就错了。你说的更像是 CSRF 。
    你要是说跨站脚本攻击,但是它的发起可以是同源的,这种 CORS 防不了。
    你描述的 CSRF 有时候根本不需要响应内容。服务器收到就好。这种 CORS 也防不了。


    而后楼主在 20 楼的问题,这是 CSP 可以解决的。你可以在 html 里给调用的 js 直接写上 hash ,浏览器会自动验证 hash 。可以应对投毒。


    如果你在乎安全,去看看 CSP ?
    chinafengzhao
        26
    chinafengzhao  
    OP
       21 天前 via iPhone
    @UnluckyNinja > 在跨域的语境下,你要搞清楚哪方是攻击方,哪方是受保护方(响应端、用户是被保护方,请求端是潜在的攻击方)。 这句话很经典,受教了
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1059 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 23:08 · PVG 07:08 · LAX 16:08 · JFK 19:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.