Rails 4 Token Keaslian

198

Saya sedang mengerjakan aplikasi Rails 4 baru (di Ruby 2.0.0-p0) ketika saya mengalami beberapa masalah token keaslian.

Sambil menulis pengontrol yang merespons json (menggunakan respond_tometode kelas), saya mendapatkan createtindakan yang mulai mendapatkan ActionController::InvalidAuthenticityTokenpengecualian ketika saya mencoba membuat catatan menggunakan curl.

Saya memastikan saya mengatur -H "Content-Type: application/json"dan saya mengatur data dengan -d "<my data here>"tetapi masih tidak berhasil.

Saya mencoba menulis controller yang sama menggunakan Rails 3.2 (pada Ruby 1.9.3) dan saya tidak mendapatkan masalah token apapun. Saya mencari-cari dan melihat ada beberapa perubahan dengan token keaslian di Rails 4. Dari apa yang saya mengerti, mereka tidak lagi secara otomatis dimasukkan ke dalam formulir lagi? Saya kira ini entah bagaimana mempengaruhi tipe konten non-HTML.

Apakah ada cara untuk mengatasi ini tanpa harus meminta formulir HTML, menyambar token keaslian, lalu membuat permintaan lain dengan token itu? Atau apakah saya benar-benar kehilangan sesuatu yang sangat jelas?

Sunting: Saya baru saja mencoba membuat catatan baru di aplikasi Rails 4 baru menggunakan perancah tanpa mengubah apa pun dan saya mengalami masalah yang sama jadi saya kira itu bukan sesuatu yang saya lakukan.

alexcoco
sumber

Jawaban:

277

Saya pikir saya baru saja menemukan jawabannya. Saya mengubah default (baru)

protect_from_forgery with: :exception

untuk

protect_from_forgery with: :null_session

sesuai komentar di ApplicationController.

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

Anda dapat melihat perbedaannya dengan melihat sumbernya request_forgery_protecton.rb, atau, lebih khusus, baris berikut:

Dalam 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

Dalam Rails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Yang akan memanggil sebagai berikut :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end
alexcoco
sumber
20
Anda dapat menghapus: dengan opsi bersama-sama,: null_session adalah default: api.rubyonrails.org/classes/ActionController/…
Casey
6
Apakah ada cara untuk menggunakan pengecualian untuk panggilan non-JSON dan sesi nol untuk panggilan JSON (alias panggilan API)?
James McMahon
@JamesMcMahon Anda mungkin dapat menulis sendiri before_actionyang memeriksa format dan apakah permintaan diverifikasi. Saya tidak tahu ada cara dibangun untuk mengatur kondisi.
alexcoco
1
Di rel 4.1.6, saya harus menentukan skip_before_action :verify_authenticity_tokenpada pengontrol aplikasi API saya juga untuk membuat ini berfungsi.
Waseem
1
Anda tidak harus menonaktifkan :verify_authenticy_tokenlagi di Rails 4.2. Defaultnya adalah :null_session, yang, seperti namanya, hanya memberi Anda permintaan tanpa sesi. Anda bisa memverifikasi permintaan melalui kunci API.
lobati
72

Daripada mematikan perlindungan csrf, lebih baik menambahkan baris kode berikut ke dalam formulir

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

dan jika Anda menggunakan form_for atau form_tag untuk menghasilkan formulir, maka secara otomatis akan menambahkan baris kode di atas dalam formulir

xiaoboa
sumber
9
Ini adalah saran yang bagus jika Anda membuat formulir, tetapi pertanyaannya mengacu pada membuat panggilan API menggunakan JSON.
James McMahon
1
Terima kasih, ini menjawab pertanyaan yang saya miliki tentang menulis kode sambil menggunakan setang!
David Routen
70

Menambahkan baris berikut ke dalam form berfungsi untuk saya:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Carlos
sumber
12
tidak benar-benar berlaku untuk panggilan api
courtimas
2
Dalam kasus saya, saya menggunakan Rails4. Saya dapat mengirimkan formulir dengan mengklik tombol kirim. Tetapi jika saya mengirimkan formulir melalui kode JS, kesalahan ini terjadi. Dan jawaban ini memperbaiki masalah saya.
Chris.Zou
2
Untuk aplikasi berbasis Rails 4.0.8 saya cukup menulis =token_tag nilatau (dalam .erb)<%= token_tag nil %>
jmarceli
1
Anda tampaknya menonaktifkan otentikasi dengan mengatur token to nil?
Carlos
apakah aman untuk melakukan ini?
Angel Garcia
33

Saya tidak berpikir itu baik untuk secara umum mematikan perlindungan CSRF selama Anda tidak secara eksklusif menerapkan API.

Ketika melihat dokumentasi Rails 4 API untuk ActionController saya menemukan bahwa Anda dapat mematikan perlindungan pemalsuan pada per controller atau per basis metode.

Misalnya untuk mematikan perlindungan CSRF untuk metode yang dapat Anda gunakan

class FooController < ApplicationController
  protect_from_forgery except: :index
roamingthings
sumber
Ini melakukannya untuk saya di Rails 4 - kesalahan dilemparkan setelah mencoba untuk menghapus. ^^
zero_cool
9

Datang di masalah yang sama. Memperbaikinya dengan menambahkan ke controller saya:

      skip_before_filter :verify_authenticity_token, if: :json_request?
pengguna1756254
sumber
metode yang tidak terdefinisi `json_request? ' untuk # <SettingsController: 0x000000030a54a8>, Ada ide?
Deano
Anda harus mendefinisikan metode di sana seperti: def json_request? request.format.json? akhir
Jai Kumar Rajput
7

Apakah kamu sudah mencoba?

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

Fitur-fitur ini ditambahkan untuk tujuan perlindungan keamanan dan pemalsuan.
Namun, untuk menjawab pertanyaan Anda, berikut adalah beberapa masukan. Anda dapat menambahkan baris ini setelah nama pengontrol Anda.

Seperti itu,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Berikut adalah beberapa jalur untuk versi rel yang berbeda.

Rel 3

skip_before_filter: verifikasi_authenticity_token

Rel 4 :

skip_before_action: verifikasi_authenticity_token


Jika Anda bermaksud untuk menonaktifkan fitur keamanan ini untuk semua rutinitas pengontrol, Anda dapat mengubah nilai protect_from_forgery menjadi : null_session pada file application_controller.rb Anda.

Seperti itu,

class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
end
Kent Aguilar
sumber
1

Jika Anda menggunakan jQuery with rails, berhati-hatilah mengizinkan masuk ke metode tanpa memverifikasi token keaslian.

jquery-ujs dapat mengelola token untuk Anda

Anda seharusnya sudah memilikinya sebagai bagian dari permata jquery-rails, tetapi Anda mungkin harus memasukkannya ke dalam application.js dengan

//= require jquery_ujs

Itu saja yang Anda butuhkan - panggilan ajax Anda sekarang harus berfungsi

Untuk informasi lebih lanjut, lihat: https://github.com/rails/jquery-ujs

pengguna1555400
sumber
1

Tambahkan authenticity_token: trueke tag formulir

Salma Gomaa
sumber
0

Ketika Anda menentukan Anda memiliki bentuk html maka Anda harus memasukkan string token otentikasi, yang harus dikirim ke controller untuk alasan keamanan. Jika Anda menggunakan helper form helper untuk menghasilkan token keaslian ditambahkan ke form sebagai berikut.

<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>

Jadi solusi untuk masalah ini adalah dengan menambahkan bidang authenticity_token atau menggunakan rel bentuk helpers daripada mengorbankan keamanan dll.

amjad
sumber
1
Terima kasih atas jawaban Anda, meskipun ini tidak menjawab pertanyaan awal. Pertanyaan yang diajukan tentang menanggapi permintaan JSON tetapi Anda memberikan solusi untuk formulir HTML dari awal. Saat membuat permintaan JSON (pikirkan API), Anda tidak mengirimkan formulir HTML dan Anda mungkin tidak memiliki akses mudah ke token keaslian.
alexcoco
kecuali jika isi dari permintaan sebenarnya JSON dalam hal ini Anda ingin mengaturnya application/json.
alexcoco
Saya mengerti jawabannya bukan apa yang Anda cari. Tetapi tujuan memberikan jawaban terkait adalah untuk membantu pengguna mencari "Masalah Keaslian" yang serupa.
amjad
maaf saya salah menghapus - "Anda dapat mengatur Content-Type: application / x-www-form-urlencoded dengan solusi di atas".
amjad
0

Semua tes saya bekerja dengan baik. Tetapi untuk beberapa alasan saya telah menetapkan variabel lingkungan saya ke non-tes:

export RAILS_ENV=something_non_test

Saya lupa menghapus variabel ini karena saya mulai mendapatkan ActionController::InvalidAuthenticityTokenpengecualian.

Setelah tidak disetel $RAILS_ENV, tes saya mulai bekerja lagi.

mridula
sumber