Rails 4 Mã xác thực


198

Tôi đang làm việc trên một ứng dụng Rails 4 mới (trên Ruby 2.0.0-p0) khi tôi gặp phải một số vấn đề về mã thông báo xác thực.

Trong khi viết một bộ điều khiển đáp ứng với json (sử dụng respond_tophương thức lớp), tôi đã có createhành động tôi bắt đầu có ActionController::InvalidAuthenticityTokenngoại lệ khi tôi cố gắng tạo một bản ghi bằng cách sử dụng curl.

Tôi chắc chắn rằng tôi đã thiết lập -H "Content-Type: application/json"và tôi thiết lập dữ liệu -d "<my data here>"nhưng vẫn không gặp may.

Tôi đã thử viết cùng một bộ điều khiển bằng Rails 3.2 (trên Ruby 1.9.3) và tôi không gặp vấn đề gì về tính xác thực của mã thông báo. Tôi đã tìm kiếm xung quanh và tôi thấy rằng có một số thay đổi với mã thông báo xác thực trong Rails 4. Từ những gì tôi hiểu, chúng không còn được tự động chèn vào biểu mẫu nữa? Tôi cho rằng điều này bằng cách nào đó ảnh hưởng đến các loại nội dung không phải HTML.

Có cách nào để khắc phục điều này mà không phải yêu cầu biểu mẫu HTML, lấy mã thông báo xác thực, sau đó thực hiện một yêu cầu khác với mã thông báo đó không? Hay tôi hoàn toàn thiếu một cái gì đó hoàn toàn rõ ràng?

Chỉnh sửa: Tôi vừa thử tạo một bản ghi mới trong ứng dụng Rails 4 mới bằng cách sử dụng một giàn giáo mà không thay đổi bất cứ điều gì và tôi đang gặp vấn đề tương tự vì vậy tôi đoán đó không phải là điều tôi đã làm.

Câu trả lời:


277

Tôi nghĩ rằng tôi chỉ cần tìm ra nó. Tôi đã thay đổi mặc định (mới)

protect_from_forgery with: :exception

đến

protect_from_forgery with: :null_session

theo nhận xét trong ApplicationController.

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

Bạn có thể thấy sự khác biệt bằng cách xem nguồn cho request_forgery_protecton.rb, hoặc cụ thể hơn là các dòng sau:

Trong Rails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

Trong Rails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Mà sẽ gọi như sau :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end

20
Bạn có thể xóa: với tất cả tùy chọn cùng nhau ,: null_session là mặc định: api.rubyonrails.org/groupes/ActionContoder/ Kẻ
Casey

6
Có cách nào để sử dụng ngoại lệ cho các cuộc gọi không phải JSON và phiên null cho các cuộc gọi JSON (còn gọi là các cuộc gọi API) không?
James McMahon

@JamesMcMahon Bạn có thể tự viết before_actionđể kiểm tra định dạng và liệu yêu cầu có được xác minh hay không. Tôi không biết bất kỳ cách xây dựng nào để đặt điều kiện.
alexcoco

1
Trong rails 4.1.6, tôi cũng phải chỉ định skip_before_action :verify_authenticity_tokentrên bộ điều khiển ứng dụng API của mình để làm cho nó hoạt động.
Waseem

1
Bạn không cần phải vô hiệu hóa :verify_authenticy_tokennữa trong Rails 4.2. Nó mặc định :null_session, như tên của nó ngụ ý, chỉ cung cấp cho bạn một yêu cầu mà không cần phiên. Thay vào đó, bạn có thể xác minh yêu cầu thông qua khóa API.
lobati

72

Thay vì tắt bảo vệ csrf, tốt hơn là thêm dòng mã sau vào biểu mẫu

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

và nếu bạn đang sử dụng form_for hoặc form_tag để tạo biểu mẫu, thì nó sẽ tự động thêm dòng mã ở trên vào biểu mẫu


9
Đây là lời khuyên tốt nếu bạn đang tạo một biểu mẫu, nhưng câu hỏi liên quan đến việc thực hiện các cuộc gọi API bằng JSON.
James McMahon

1
Mặc dù vậy, cảm ơn bạn, điều này đã trả lời một câu hỏi tôi có về việc viết mã tay trong khi sử dụng tay cầm!
David Routen

70

Thêm dòng sau vào mẫu làm việc cho tôi:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

12
không thực sự áp dụng cho các cuộc gọi api
Courtimas

2
Trong trường hợp của tôi, tôi đang sử dụng Rails4. Tôi có thể gửi biểu mẫu bằng cách nhấp vào nút gửi. Nhưng nếu tôi gửi biểu mẫu thông qua mã JS, lỗi này xảy ra. Và câu trả lời này đã khắc phục vấn đề cho tôi.
Chris.Zou

2
Đối với Ứng dụng dựa trên Rails 4.0.8 của tôi, nó đủ để viết =token_tag nilhoặc (bằng .erb)<%= token_tag nil %>
jmarceli

1
Bạn dường như đang vô hiệu hóa xác thực bằng cách đặt mã thông báo thành không?
Carlos

Có an toàn để làm điều này?
Thiên thần Garcia

33

Tôi không nghĩ rằng nói chung là tốt để tắt bảo vệ CSRF miễn là bạn không thực hiện độc quyền API.

Khi xem tài liệu API Rails 4 cho ActionContoder tôi thấy rằng bạn có thể tắt bảo vệ giả mạo trên mỗi bộ điều khiển hoặc trên mỗi cơ sở phương thức.

Ví dụ: để tắt bảo vệ CSRF cho các phương thức bạn có thể sử dụng

class FooController < ApplicationController
  protect_from_forgery except: :index

Điều này đã làm điều đó cho tôi trong Rails 4 - lỗi bị ném sau khi cố gắng xóa. ^^
zero_cool

9

Đã đến cùng một vấn đề. Đã sửa nó bằng cách thêm vào bộ điều khiển của tôi:

      skip_before_filter :verify_authenticity_token, if: :json_request?

phương pháp không xác định `json_Vquest? ' cho # <Cài đặt Trình điều khiển: 0x000000030a54a8>, có ý tưởng nào không?
Deano

Bạn phải xác định một phương thức ở đó như: def json_Vquest? request.format.json? kết thúc
Jai Kumar Rajput

7

Bạn đã thử chưa?

 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }

4

Tài liệu chính thức này - nói về cách tắt bảo vệ giả mạo cho api đúng cách http://api.rubyonrails.org/groupes/ActionControll/RequestForgeryProtection.html


1
Điều đó đúng, nhưng câu trả lời là từ năm 2013 - và mọi thứ thay đổi. Và trong khi câu trả lời được chấp nhận chính thức của bạn là tốt - liên kết của tôi chỉ đơn giản là cung cấp tốt hơn về tổng quan sâu sắc của chủ đề
konung


2

Những tính năng này đã được thêm vào cho mục đích bảo vệ và giả mạo.
Tuy nhiên, để trả lời câu hỏi của bạn, đây là một số đầu vào. Bạn có thể thêm các dòng này sau tên bộ điều khiển của bạn.

Như vậy

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Dưới đây là một số dòng cho các phiên bản khác nhau của đường ray.

Đường ray 3

Skip_b Before_filter: verify_authenticity_token

Đường ray 4 :

Skip_b Before_action: verify_authenticity_token


Nếu bạn có ý định vô hiệu hóa tính năng bảo mật này cho tất cả các thói quen của bộ điều khiển, bạn có thể thay đổi giá trị của Protect_from_forgery thành : null_session trên tệp application_controll.rb của bạn.

Như vậy

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end

1

Nếu bạn đang sử dụng jQuery với đường ray, hãy cảnh giác khi cho phép nhập vào các phương thức mà không cần xác minh mã thông báo xác thực.

jquery-ujs có thể quản lý mã thông báo cho bạn

Bạn nên có nó như là một phần của đá quý jquery-rails, nhưng bạn có thể cần đưa nó vào application.js với

//= require jquery_ujs

Đó là tất cả những gì bạn cần - cuộc gọi ajax của bạn sẽ hoạt động

Để biết thêm thông tin, hãy xem: https://github.com/rails/jquery-ujs



0

Khi bạn xác định bạn sở hữu biểu mẫu html thì bạn phải bao gồm chuỗi mã thông báo xác thực, mã này phải được gửi đến bộ điều khiển vì lý do bảo mật. Nếu bạn sử dụng trình trợ giúp biểu mẫu đường ray để tạo mã thông báo xác thực được thêm vào biểu mẫu như sau.

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
  </div>
    ...
</form>

Vì vậy, giải pháp cho vấn đề này là thêm trường xác thực_token hoặc sử dụng trình trợ giúp biểu mẫu rails thay vì làm tổn hại đến bảo mật, v.v.


1
Cảm ơn câu trả lời của bạn, mặc dù điều này không trả lời câu hỏi ban đầu. Câu hỏi được hỏi về việc trả lời các yêu cầu JSON nhưng bạn đang cung cấp giải pháp cho biểu mẫu HTML từ đầu. Khi thực hiện các yêu cầu JSON (nghĩ API), bạn không gửi biểu mẫu HTML và bạn có thể không có quyền truy cập dễ dàng vào mã thông báo xác thực.
alexcoco

trừ khi nội dung của yêu cầu thực sự là JSON trong trường hợp bạn muốn đặt nó thành application/json.
alexcoco

Tôi hiểu câu trả lời không chính xác những gì bạn đang tìm kiếm. Nhưng mục đích của việc đưa ra câu trả lời liên quan là giúp người dùng tìm kiếm "Các vấn đề xác thực" tương tự.
amjad

xin lỗi tôi đã xóa nhầm - "bạn có thể đặt Loại nội dung: application / x-www-form-urlencoding với giải pháp trên".
amjad

0

Tất cả các bài kiểm tra của tôi đã hoạt động tốt. Nhưng vì một số lý do, tôi đã đặt biến môi trường của mình thành không kiểm tra:

export RAILS_ENV=something_non_test

Tôi quên không đặt biến này vì tôi bắt đầu có ActionController::InvalidAuthenticityTokenngoại lệ.

Sau khi bỏ đặt $RAILS_ENV, các bài kiểm tra của tôi bắt đầu hoạt động trở lại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.