te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>Rails Protect From Forgery with Javascript - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Rails Protect From Forgery with Javascript - Stack Overflow

programmeradmin4浏览0评论

I am running into a weird CSRF where I am trying to access a javascript file uploaded on my rails server. I have a controller such as:

class SomeController < ApplicationController
  def show
    some_path = "/some/js/file/on/disk.js"
    send_file(some_path, type: "text/javascript", disposition: :inline)
  end
end

However when navigating to http://localhost:3000/somes/1 I get the error message:

Security warning: an embedded tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.

Extracted source (around line #225):

    if marked_for_same_origin_verification? && non_xhr_javascript_response?
      logger.warn CROSS_ORIGIN_JAVASCRIPT_WARNING if logger
      raise ActionController::InvalidCrossOriginRequest, CROSS_ORIGIN_JAVASCRIPT_WARNING
    end
  end

Note that I am accessing this page directly which means that there is no layout so I cannot include a CSRF token in my layout.

Is there something that needs to be done differently to correctly access this resource?

EDIT: Per ment request, I have added the Full Trace below.

actionpack (4.2.6) lib/action_controller/metal/request_forgery_protection.rb:225:in verify_same_origin_request' activesupport (4.2.6) lib/active_support/callbacks.rb:432:inblock in make_lambda' activesupport (4.2.6) lib/active_support/callbacks.rb:239:in block in halting' activesupport (4.2.6) lib/active_support/callbacks.rb:506:in block in call' activesupport (4.2.6) lib/active_support/callbacks.rb:506:in each' activesupport (4.2.6) lib/active_support/callbacks.rb:506:incall' activesupport (4.2.6) lib/active_support/callbacks.rb:92:in __run_callbacks__' activesupport (4.2.6) lib/active_support/callbacks.rb:778:in _run_process_action_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.6) lib/abstract_controller/callbacks.rb:19:inprocess_action' actionpack (4.2.6) lib/action_controller/metal/rescue.rb:29:in process_action' actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:32:inblock in process_action' activesupport (4.2.6) lib/active_support/notifications.rb:164:in block in instrument' activesupport (4.2.6) lib/active_support/notifications/instrumenter.rb:20:ininstrument' activesupport (4.2.6) lib/active_support/notifications.rb:164:in instrument' actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:30:inprocess_action' actionpack (4.2.6) lib/action_controller/metal/params_wrapper.rb:250:in process_action' activerecord (4.2.6) lib/active_record/railties/controller_runtime.rb:18:in process_action' actionpack (4.2.6) lib/abstract_controller/base.rb:137:in process' actionview (4.2.6) lib/action_view/rendering.rb:30:inprocess' actionpack (4.2.6) lib/action_controller/metal.rb:196:in dispatch' actionpack (4.2.6) lib/action_controller/metal/rack_delegation.rb:13:indispatch' actionpack (4.2.6) lib/action_controller/metal.rb:237:in block in action' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:74:indispatch' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:43:in serve' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:43:inblock in serve' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:30:in each' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:30:inserve' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:817:in call' bullet (5.1.1) lib/bullet/rack.rb:12:incall' warden (1.2.6) lib/warden/manager.rb:35:in block in call' warden (1.2.6) lib/warden/manager.rb:34:incatch' warden (1.2.6) lib/warden/manager.rb:34:in call' rack (1.6.4) lib/rack/etag.rb:24:in call' rack (1.6.4) lib/rack/conditionalget.rb:25:in call' rack (1.6.4) lib/rack/head.rb:13:incall' actionpack (4.2.6) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.2.6) lib/action_dispatch/middleware/flash.rb:260:in call' rack (1.6.4) lib/rack/session/abstract/id.rb:225:in context' rack (1.6.4) lib/rack/session/abstract/id.rb:220:incall' actionpack (4.2.6) lib/action_dispatch/middleware/cookies.rb:560:in call' activerecord (4.2.6) lib/active_record/query_cache.rb:36:incall' activerecord (4.2.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in call' activerecord (4.2.6) lib/active_record/migration.rb:377:in call' actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:29:in block in call' activesupport (4.2.6) lib/active_support/callbacks.rb:88:in run_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:778:in _run_call_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:27:in call' actionpack (4.2.6) lib/action_dispatch/middleware/reloader.rb:73:incall' actionpack (4.2.6) lib/action_dispatch/middleware/remote_ip.rb:78:in call' actionpack (4.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:17:incall' web-console (2.3.0) lib/web_console/middleware.rb:28:in block in call' web-console (2.3.0) lib/web_console/middleware.rb:18:incatch' web-console (2.3.0) lib/web_console/middleware.rb:18:in call' actionpack (4.2.6) lib/action_dispatch/middleware/show_exceptions.rb:30:incall' railties (4.2.6) lib/rails/rack/logger.rb:38:in call_app' railties (4.2.6) lib/rails/rack/logger.rb:20:inblock in call' activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in block in tagged' activesupport (4.2.6) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in tagged' railties (4.2.6) lib/rails/rack/logger.rb:20:incall' quiet_assets (1.1.0) lib/quiet_assets.rb:27:in call_with_quiet_assets' request_store (1.3.1) lib/request_store/middleware.rb:9:incall' actionpack (4.2.6) lib/action_dispatch/middleware/request_id.rb:21:in call' rack (1.6.4) lib/rack/methodoverride.rb:22:incall' rack (1.6.4) lib/rack/runtime.rb:18:in call' activesupport (4.2.6) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in call' rack (1.6.4) lib/rack/lock.rb:17:in call' actionpack (4.2.6) lib/action_dispatch/middleware/static.rb:120:incall' rack (1.6.4) lib/rack/sendfile.rb:113:in call' railties (4.2.6) lib/rails/engine.rb:518:incall' railties (4.2.6) lib/rails/application.rb:165:in call' rack (1.6.4) lib/rack/content_length.rb:15:incall' puma (3.5.0) lib/puma/configuration.rb:225:in call' puma (3.5.0) lib/puma/server.rb:569:inhandle_request' puma (3.5.0) lib/puma/server.rb:406:in process_client' puma (3.5.0) lib/puma/server.rb:271:inblock in run' puma (3.5.0) lib/puma/thread_pool.rb:116:in `block in spawn_thread'

I am running into a weird CSRF where I am trying to access a javascript file uploaded on my rails server. I have a controller such as:

class SomeController < ApplicationController
  def show
    some_path = "/some/js/file/on/disk.js"
    send_file(some_path, type: "text/javascript", disposition: :inline)
  end
end

However when navigating to http://localhost:3000/somes/1 I get the error message:

Security warning: an embedded tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.

Extracted source (around line #225):

    if marked_for_same_origin_verification? && non_xhr_javascript_response?
      logger.warn CROSS_ORIGIN_JAVASCRIPT_WARNING if logger
      raise ActionController::InvalidCrossOriginRequest, CROSS_ORIGIN_JAVASCRIPT_WARNING
    end
  end

Note that I am accessing this page directly which means that there is no layout so I cannot include a CSRF token in my layout.

Is there something that needs to be done differently to correctly access this resource?

EDIT: Per ment request, I have added the Full Trace below.

actionpack (4.2.6) lib/action_controller/metal/request_forgery_protection.rb:225:in verify_same_origin_request' activesupport (4.2.6) lib/active_support/callbacks.rb:432:inblock in make_lambda' activesupport (4.2.6) lib/active_support/callbacks.rb:239:in block in halting' activesupport (4.2.6) lib/active_support/callbacks.rb:506:in block in call' activesupport (4.2.6) lib/active_support/callbacks.rb:506:in each' activesupport (4.2.6) lib/active_support/callbacks.rb:506:incall' activesupport (4.2.6) lib/active_support/callbacks.rb:92:in __run_callbacks__' activesupport (4.2.6) lib/active_support/callbacks.rb:778:in _run_process_action_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.6) lib/abstract_controller/callbacks.rb:19:inprocess_action' actionpack (4.2.6) lib/action_controller/metal/rescue.rb:29:in process_action' actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:32:inblock in process_action' activesupport (4.2.6) lib/active_support/notifications.rb:164:in block in instrument' activesupport (4.2.6) lib/active_support/notifications/instrumenter.rb:20:ininstrument' activesupport (4.2.6) lib/active_support/notifications.rb:164:in instrument' actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:30:inprocess_action' actionpack (4.2.6) lib/action_controller/metal/params_wrapper.rb:250:in process_action' activerecord (4.2.6) lib/active_record/railties/controller_runtime.rb:18:in process_action' actionpack (4.2.6) lib/abstract_controller/base.rb:137:in process' actionview (4.2.6) lib/action_view/rendering.rb:30:inprocess' actionpack (4.2.6) lib/action_controller/metal.rb:196:in dispatch' actionpack (4.2.6) lib/action_controller/metal/rack_delegation.rb:13:indispatch' actionpack (4.2.6) lib/action_controller/metal.rb:237:in block in action' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:74:indispatch' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:43:in serve' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:43:inblock in serve' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:30:in each' actionpack (4.2.6) lib/action_dispatch/journey/router.rb:30:inserve' actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:817:in call' bullet (5.1.1) lib/bullet/rack.rb:12:incall' warden (1.2.6) lib/warden/manager.rb:35:in block in call' warden (1.2.6) lib/warden/manager.rb:34:incatch' warden (1.2.6) lib/warden/manager.rb:34:in call' rack (1.6.4) lib/rack/etag.rb:24:in call' rack (1.6.4) lib/rack/conditionalget.rb:25:in call' rack (1.6.4) lib/rack/head.rb:13:incall' actionpack (4.2.6) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.2.6) lib/action_dispatch/middleware/flash.rb:260:in call' rack (1.6.4) lib/rack/session/abstract/id.rb:225:in context' rack (1.6.4) lib/rack/session/abstract/id.rb:220:incall' actionpack (4.2.6) lib/action_dispatch/middleware/cookies.rb:560:in call' activerecord (4.2.6) lib/active_record/query_cache.rb:36:incall' activerecord (4.2.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in call' activerecord (4.2.6) lib/active_record/migration.rb:377:in call' actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:29:in block in call' activesupport (4.2.6) lib/active_support/callbacks.rb:88:in run_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:778:in _run_call_callbacks' activesupport (4.2.6) lib/active_support/callbacks.rb:81:in run_callbacks' actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:27:in call' actionpack (4.2.6) lib/action_dispatch/middleware/reloader.rb:73:incall' actionpack (4.2.6) lib/action_dispatch/middleware/remote_ip.rb:78:in call' actionpack (4.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:17:incall' web-console (2.3.0) lib/web_console/middleware.rb:28:in block in call' web-console (2.3.0) lib/web_console/middleware.rb:18:incatch' web-console (2.3.0) lib/web_console/middleware.rb:18:in call' actionpack (4.2.6) lib/action_dispatch/middleware/show_exceptions.rb:30:incall' railties (4.2.6) lib/rails/rack/logger.rb:38:in call_app' railties (4.2.6) lib/rails/rack/logger.rb:20:inblock in call' activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in block in tagged' activesupport (4.2.6) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in tagged' railties (4.2.6) lib/rails/rack/logger.rb:20:incall' quiet_assets (1.1.0) lib/quiet_assets.rb:27:in call_with_quiet_assets' request_store (1.3.1) lib/request_store/middleware.rb:9:incall' actionpack (4.2.6) lib/action_dispatch/middleware/request_id.rb:21:in call' rack (1.6.4) lib/rack/methodoverride.rb:22:incall' rack (1.6.4) lib/rack/runtime.rb:18:in call' activesupport (4.2.6) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in call' rack (1.6.4) lib/rack/lock.rb:17:in call' actionpack (4.2.6) lib/action_dispatch/middleware/static.rb:120:incall' rack (1.6.4) lib/rack/sendfile.rb:113:in call' railties (4.2.6) lib/rails/engine.rb:518:incall' railties (4.2.6) lib/rails/application.rb:165:in call' rack (1.6.4) lib/rack/content_length.rb:15:incall' puma (3.5.0) lib/puma/configuration.rb:225:in call' puma (3.5.0) lib/puma/server.rb:569:inhandle_request' puma (3.5.0) lib/puma/server.rb:406:in process_client' puma (3.5.0) lib/puma/server.rb:271:inblock in run' puma (3.5.0) lib/puma/thread_pool.rb:116:in `block in spawn_thread'

Share Improve this question edited Sep 16, 2016 at 19:43 Lilith Daemon asked Sep 12, 2016 at 16:06 Lilith DaemonLilith Daemon 1,4732 gold badges19 silver badges37 bronze badges 6
  • You are trying to access this resource from where and how? What's the name of the file that source es from? – Leonel Galán Commented Sep 12, 2016 at 16:14
  • @Leito I am not really sure how the file name is relevant, but it is called sketch.js and stored utilizing Carrierwave – Lilith Daemon Commented Sep 14, 2016 at 18:13
  • I meant the file where the error is occurring. The one where line #225 is? – Leonel Galán Commented Sep 15, 2016 at 19:06
  • @Leito Idk then, its some file in rails I am assuming. (The shown code isn't mine, and it didn't give any further information.) – Lilith Daemon Commented Sep 16, 2016 at 1:14
  • @Leito I added the full trace in case that helps. Its causing an error somewhere in rails itself. – Lilith Daemon Commented Sep 16, 2016 at 19:44
 |  Show 1 more ment

5 Answers 5

Reset to default 3

I won't ask why you're using a controller to send a javascript file to the browser even though that doesn't seem like a good idea. I hope these suggestions help.

You could try

class SomeController < ApplicationController
  def show
    some_path = "/some/js/file/on/disk.js"

    respond_to do |format|
      format.js {
        send_file(some_path, type: "text/javascript", disposition: :inline) 
      }
      format.html {
        "Html request from browser. Try sending a js request to get <Javascript>"
      }
    end
  end
end

The other answer is to change the CSRF handling. This is similar to the answer Michal already suggested,

    class SomeController < ApplicationController
        protect_from_forgery except: :show 
        ...
    end

In my opinion changing CSRF handling approach is much broader in scope. Disabling CSRF for a given method in the controller exposes things that you may not want exposed.


Here are some additional suggestions.

It may be old fashioned, but curl enables one to gain plete control of the HTTP request headers as well as seeing the full HTTP response. By calling curl -H "Content-Type: application/javascript" http://someurl/here/1 you will be able to see exactly what's happening and why your browser is unable to serve the requested javascript file, or if there is a workaround.

Lastly, if you're trying to serve up static (javascript) files in Rails, there is a lot of extra overhead and potential security risk using a controller to perform that action. Unless there is a very good reason for using the controller, a simpler solution would be to store the files in a sub-directory of the ./public directory on the server, so that anyone and everyone can read the file(s). When you deploy the application to a production environment this could save even more overhead, but that's beyond the scope of your original question.

Good luck!

As error message says, you need to disable forgery protection for this action.

class SomeController < ApplicationController
  skip_before_action :verify_authenticity_token, only: :show

  def show
    some_path = "/some/js/file/on/disk.js"
    send_file(some_path, type: "text/javascript", disposition: :inline)
  end
end

Some suggestions:

1) Make sure to add <%= csrf_meta_tag %>in your layout

2) Make sure that you are including the csrf-token hidden field. For instance if you are using a form in the show view. Normally the form builders do it automatically.

3) Set application/javascript" in the send_file

if request.format.js?
   send_file(assetfilename, type: 'application/javascript')
else
   send_file(assetfilename)
end

Checking out the conditions that fire the error:

marked_for_same_origin_verification? && non_xhr_javascript_response?

I went to the source and found:

  # GET requests are checked for cross-origin JavaScript after rendering.
  def mark_for_same_origin_verification!
    @marked_for_same_origin_verification = request.get?
  end

  # If the `verify_authenticity_token` before_action ran, verify that
  # JavaScript responses are only served to same-origin GET requests.
  def marked_for_same_origin_verification?
    @marked_for_same_origin_verification ||= false
  end

So that seems to e back true if it's a GET request.

Meanwhile,

  def non_xhr_javascript_response?
    content_type =~ %r(\Atext/javascript) && !request.xhr?
  end

Which seems to describe your response--a non XHR request yielding a file with text/javascript content.

I suppose that you could avoid this (other than by skipping verify_authenticity_token) by forking a branch of rails and changing one of those conditions, or else introducing some layout so the response isn't just javascript.

The issue is that the check in Rails done in verify_same_origin_request that you quote in your question does not actually check the origin. Instead it only checks if (1) it is a GET request, and (2) it is not an XHR request. Your use case satisfies both of these, so the error is raised.

I don't know why the code works in this way. But it does.

Rather than skip the forgery protection pletely, you can just skip the call to verify_same_origin_request.

You can do so by adding this to the top of your controller:

class SomeController < ApplicationController
   skip_after_action :verify_same_origin_request
发布评论

评论列表(0)

  1. 暂无评论