Cloudfront CORS问题在Rails应用程序中提供字体 [英] Cloudfront CORS issue serving fonts on Rails application

查看:233
本文介绍了Cloudfront CORS问题在Rails应用程序中提供字体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



 来自原始的字体https:// xxx .cloudfront.net已被阻止加载跨源资源共享策略:请求的资源上没有Access-Control-Allow-Origin标头。 Origin'https://www.example.com'因此不被允许访问。 

我已经试过了一切:


  • 我已安装 font_assets gem

  • 配置application.rb文件

    $ $ p $ $ $ codeonfig.font_assets.origin ='http://example.com


  • Cloudfront上的白名单标题,详见这篇文章

      Access-Control-Allow-Origin 
    Access-Control-Allow-Methods
    Access-Control-Allow-Headers
    Access-Control-Max-Age



    $ b

    但没有,零,nada。

    我在Heroku上使用Rails 4.1。解决方案

    原因有两个:


    1. CloudFront是镜像我们的Rails应用程序的响应标题需要你扭转你的想法。 CORS协议很难理解,但是现在你必须在两个层面上进行:在浏览器和CloudFront之间(当我们的Rails应用程序使用它作为CDN时)​​,以及在浏览器和Rails应用程序之间(当一些恶意网站想滥用我们)。

      CORS实际上是关于浏览器与网页想要访问的第三方资源之间的对话。 (在我们的用例中,这就是CloudFront CDN,为我们的应用程序提供资源)。但是,由于CloudFront从我们的应用程序获取其访问控制响应头,因此我们的应用程序需要为这些头提供这些头就好像是CloudFront交谈,而同时 不会授予权限,从而使自身暴露于导致首先开发同源策略/ CORS的滥用类型。特别是,我们不应在我们的网站上授予 * 访问 * 资源。


    2. 我在那里发现了那么多过时的信息 - 一条无尽的博客文章和SO线索。 CloudFront已经大幅改善了对CORS的支持,尽管这些支持还不够完善。 (CORS应该是真正的开箱即用的处理方式)。而且宝石本身已经进化了。

    3. 我的b $ b

    我的setup:在Heroku上运行的Rails 4.1.15,资源来自CloudFront。我的应用程序在www上同时响应http和https。和区域顶点,而不做任何重定向。



    我简要地看了一下问题中提到的font_assets gem,但很快就放弃了它,更重要的一点。我不想简单地打开所有的起源和所有的路径,因为这将打败CORS和同源政策的安全性,所以我需要能够指定我允许的几个起源。最后,我个人更喜欢通过单独的 config / initializers / *。rb 文件来配置Rails,而不是编辑标准的配置文件(比如 config.ru config / application.rb )综合起来,这里是我的解决方案,我相信是最好的,截至2016-04-16 :


    1. Gemfile

      <$ p $







      CORS协议在Rack中间件中。
      除了在批准的起源上设置Access-Control-Allow-Origin和相关头文件,它还添加了一个 Vary:Origin 响应头,指示CloudFront缓存响应(包括响应头)分别为每个来源。这是至关重要的,当我们的网站可以通过多个来源(例如通过HTTP和HTTPS,并通过WWW和裸露的域名)

      strong> config / initializers / rack-cors.rb

        ##配置Rack CORS中间件,使CloudFront可以服务我们的资产。 
      ##如果已定义,请参阅https://github.com/cyu/rack-cors

      。 Rack :: Cors
      Rails.configuration.middleware.insert_before 0,Rack :: Cors do
      allow
      originins%w [
      https://example.com
      http://example.com
      https://www.example.com
      http://www.example.com
      https://example-staging.herokuapp.com
      http://example-staging.herokuapp.com
      ]
      资源'/ assets / *'
      结束
      结束
      结束

      这告诉浏览器它可以访问我们Rails应用程序中的资源(以及在CloudFront上的扩展,因为它镜像了我们)代表我们的Rails应用程序(而不是代表恶意网站),并且只为 / assets / url(和<我们的控制器不是)。换句话说,允许CloudFront为资产提供服务,但是不要超出我们的要求。

      注意:


      • 我尝试在rack-timeout之后插入这个,而不是在中间件链的头部。
        尽管
        具有相同的中间件(除了Honeybadger),但是它并没有在Heroku上投入。

      • 起源列表也可以做为正则表达式。
        请注意在字符串末尾固定模式。

         原点[
        / \ Ahttps?:\ / \ /(www \。)?example\.com\z /,
        /\Ahttps?:\/\/example-staging\.herokuapp\\ \\ .com \ z /
        ]

        但是我认为只要阅读文字字符串。


    2. 配置CloudFront将浏览器的Origin请求标头传递给我们的Rails应用程序。奇怪的是,无论我们是否在这里添加它,似乎CloudFront都会将Origin头文件从浏览器转发到我们的Rails应用程序,而不管 但CloudFront只有在明确将Origin添加到标题白名单(截至2016年4月)的情况下,才会授予我们的应用程序的 Vary:Origin 缓存指令。



      请求标题白名单被隐藏了。

      如果分布已经存在,您可以在以下位置找到它:




      • https://console.aws.amazon.com/cloudfront/home#distributions

      • 选择分配

      • 点击分配设置

      • 转至行为选项卡
      • 选择行为可能只有一个)
      • 点击编辑

      • 转发标题:白名单

      • 白名单标题:选择来源,然后点击添加>>



        如果您尚未创建发行版,请在以下位置创建发行版:


        • https://console.aws.amazon.com/cloudfront/home#distributions> https://console.aws.amazon.com/cloudfront/home#distributions


        • (为了完整性和可重复性,我列出了所有我从默认设置中更改的设置,但是白名单设置是唯一的(与RTMP相关)

        • 传递方法:Web(不是RTMP)


        • 来源设置




          • 原始域名:example.com

          • 原始SSL协议:TLSv1.2仅适用于

          • 源协议策略:仅适用于HTTPS


          • 浏览器协议策略:将HTTP重定向到HTTPS


          • 转发标题:白名单
          • 自动压缩对象:是



    更改所有这些内容后,请记住,任何旧的缓存值可能需要一段时间才能从CloudFront过期。您可以通过转到CloudFront分发的无效选项卡并为 * 创建无效,从而显式地使缓存的资产无效。

    I keep receiving this error message from the console when visiting my website:

    font from origin 'https://xxx.cloudfront.net' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.example.com' is therefore not allowed access.
    

    I've tried everything:

    • I've installed the font_assets gem
    • configured the application.rb file

      config.font_assets.origin = 'http://example.com'
      

    • Whitelisted Headers on Cloudfront as explained in this article to

      Access-Control-Allow-Origin
      Access-Control-Allow-Methods
      Access-Control-Allow-Headers
      Access-Control-Max-Age
      

    But nothing, zero, nada.

    I'm using Rails 4.1 on Heroku.

    解决方案

    This was an incredibly difficult issue to deal with, for two reasons:

    1. The fact that CloudFront is mirroring our Rails app’s response headers requires you to twist your mind around. The CORS protocol is hard enough to understand as it is, but now you have to follow it at two levels: between the browser and CloudFront (when our Rails app uses it as a CDN), and between the browser and our Rails app (when some malicious site wants to abuse us).

      CORS is really about a dialog between the browser and the 3rd-party resources a web page wants to access. (In our use-case, that’s the CloudFront CDN, serving assets for our app.) But since CloudFront gets its Access-Control response headers from our app, our app needs to serve those headers as if it is CloudFront talking, and simultaneously not grant permissions that would expose itself to the type of abuse that led to the Same-Origin Policy / CORS being developed in the first place. In particular, we should not grant * access to * resources on our site.

    2. I found so much outdated information out there -- an endless line of blog posts and SO threads. CloudFront has improved its CORS support significantly since many of those posts, although it is still not perfect. (CORS should really be handled out-of-the-box.) And the gems themselves have evolved.

    My setup: Rails 4.1.15 running on Heroku, with assets served from CloudFront. My app responds to both http and https, on both "www." and the zone apex, without doing any redirection.

    I looked briefly at the font_assets gem mentioned in the question, but quickly dropped it in favor of rack-cors, which seemed more on point. I did not want to simply open up all origins and all paths, as that would defeat the point of CORS and the security of the Same-Origin Policy, so I needed to be able to specify the few origins I would allow. Finally, I personally favor configuring Rails via individual config/initializers/*.rb files rather than editing the standard config files (like config.ru or config/application.rb) Putting all that together, here is my solution, which I believe is the best available, as of 2016-04-16:

    1. Gemfile

      gem "rack-cors"
      

      The rack-cors gem implements the CORS protocol in a Rack middleware. In addition to setting Access-Control-Allow-Origin and related headers on approved origins, it adds a Vary: Origin response header, directing CloudFront to cache the responses (including the response headers) for each origin separately. This is crucial when our site is accessible via multiple origins (e.g. via both http and https, and via both "www." and the bare domain)

    2. config/initializers/rack-cors.rb

      ## Configure Rack CORS Middleware, so that CloudFront can serve our assets.
      ## See https://github.com/cyu/rack-cors
      
      if defined? Rack::Cors
          Rails.configuration.middleware.insert_before 0, Rack::Cors do
              allow do
                  origins %w[
                      https://example.com
                       http://example.com
                      https://www.example.com
                       http://www.example.com
                      https://example-staging.herokuapp.com
                       http://example-staging.herokuapp.com
                  ]
                  resource '/assets/*'
              end
          end
      end
      

      This tells the browser that it may access resources on our Rails app (and by extension, on CloudFront, since it is mirroring us) only on behalf of our Rails app (and not on behalf of malicious-site.com) and only for /assets/ urls (and not for our controllers). In other words, allow CloudFront to serve assets but don't open the door any more than we have to.

      Notes:

      • I tried inserting this after rack-timeout instead of at the head of the middleware chain. It worked on dev but was not kicking in on Heroku, despite having the same middleware (other than Honeybadger).
      • The origins list could also be done as Regexps. Be careful to anchor patterns at the end-of-string.

        origins [
            /\Ahttps?:\/\/(www\.)?example\.com\z/,
            /\Ahttps?:\/\/example-staging\.herokuapp\.com\z/
        ]
        

        but I think it’s easier just to read literal strings.

    3. Configure CloudFront to pass the browser's Origin request header on to our Rails app.

      Strangely, it appears that CloudFront forwards the Origin header from the browser to our Rails app regardless whether we add it here, but that CloudFront honors our app’s Vary: Origin caching directive only if Origin is explicitly added to the headers whitelist (as of April 2016).

      The request header whitelist is kind of buried.

      If the distribution already exists, you can find it at:


      If you have not created the distribution yet, create it at:

      • https://console.aws.amazon.com/cloudfront/home#distributions
      • Click Create Distribution

        (For the sake of completeness and reproducibility, I'm listing all the settings I changed from the defaults, however the Whitelist settings are the only ones that are relevant to this discussion)

      • Delivery Method: Web (not RTMP)

      • Origin Settings

        • Origin Domain Name: example.com
        • Origin SSL Protocols: TLSv1.2 ONLY
        • Origin Protocol Policy: HTTPS only
      • Default Cache Behavior Settings

        • Viewer Protocol Policy: Redirect HTTP to HTTPS
        • Forward Headers: Whitelist
        • Whitelist Headers: Select Origin and click Add >>
        • Compress Objects Automatically: Yes

    After changing all these things, remember that it can take some time for any old, cached values to expire from CloudFront. You can explicitly invalidate cached assets by going to the CloudFront distribution's Invalidations tab and creating an invalidation for *.

    这篇关于Cloudfront CORS问题在Rails应用程序中提供字体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆