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

CROS 同源问题的一些疑问

  •  
  •   chinafengzhao · 6 天前 · 1919 次点击

    最近在学习 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  
       6 天前
    我理解所谓「同源策略」是用来防止 CSRF 的而不是 XSS 的吧
    FlyaiF
        2
    FlyaiF  
    PRO
       6 天前
    应该是为了防止浏览器里边进行一些假冒的网站,引导用户做一些用户意料外的操作吧
    hurrytospring
        3
    hurrytospring  
       6 天前   ❤️ 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  
       6 天前
    这好比就是正规浏览器遵守的一个保护用户的规则而已吧。

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

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

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

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

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

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



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


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

    协议或者说浏览器要求带这个头部之类的,他怎么判断这个是不是普通请求呢?有些请求里面有 cookie 不代表这是带凭证吧。
    @GeruzoniAnsasu
    unco020511
        18
    unco020511  
       6 天前
    1 的前提是你主动同意黑客这么干,或者说你就是黑客. 比如你主动在电脑中设置代理,并主动安装根证书到电脑,这样就你的 proxy 就可以随意修改 https 的请求和响应. 更进一步,你直接将你的电脑权限交给黑客.所以 1 已经超出了浏览器同源政策的范畴了
    2 的话你可以理解是一个额外安全要求,附带身份凭证会认为是敏感信息,所以有一个额外的安全规定.
    不过现在用户凭证很多都不用 cookie 之类的,你想放到哪都可以,比如额外搞个 header 附带 token.
    浏览器是一个 httpClicent,当然知道你发送的请求细节,包括 https 的握手加密等细节都是浏览器去实现的,它自然知道,具体到开发中,就是设置 withCredentials 的值,你设置为 true 就认为你带了
    chinafengzhao
        19
    chinafengzhao  
    OP
       6 天前
    以 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
       6 天前
    @unco020511 其实第一个情况,要考虑到类似 jscdn 这种网站到期了被抢注了,这种域名被篡改了之类的,我做为黑客不一定要中间人攻击请求报文或响应报文,我可能攻击了类似 CDN 这种。 比如说我攻破大家都在用的 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> 假设这是我的恶意脚本,在这脚本里面去请求我的网站呢。
    chinafengzhao
        21
    chinafengzhao  
    OP
       6 天前
    @unco020511 是的,你这个第二点说的很对,用户凭证这个东西不是标准,每个网站实现都不一样,所以我才对这个 MDN 里面关于用户凭证对 Access-Control- 各种头部的限制和要求不太理解。 有点疑惑。
    dorothyREN
        22
    dorothyREN  
       6 天前
    简单请求没有跨域的问题吧
    GeruzoniAnsasu
        23
    GeruzoniAnsasu  
       6 天前
    @chinafengzhao

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

    (随收一搜)
    UnluckyNinja
        24
    UnluckyNinja  
       5 天前
    假设跨域情景下的三个角色:用户(以及使用的浏览器),用户访问的网站 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  
       5 天前
    我不得不说,很多人理解就错了。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
       5 天前 via iPhone
    @UnluckyNinja > 在跨域的语境下,你要搞清楚哪方是攻击方,哪方是受保护方(响应端、用户是被保护方,请求端是潜在的攻击方)。 这句话很经典,受教了
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2466 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 15:51 · PVG 23:51 · LAX 08:51 · JFK 11:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.