Rails: POST isteğinde bulunurken CSRF jetonunun gerçekliği doğrulanamıyor


91

POST requestYerel geliştiricime şunun gibi yapmak istiyorum:

  HTTParty.post('http://localhost:3000/fetch_heroku',
                :body => {:type => 'product'},)

Ancak sunucu konsolundan bildirir

Started POST "/fetch_heroku" for 127.0.0.1 at 2016-02-03 23:33:39 +0800
  ActiveRecord::SchemaMigration Load (0.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by AdminController#fetch_heroku as */*
  Parameters: {"type"=>"product"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

İşte denetleyicim ve rota kurulumum, oldukça basit.

  def fetch_heroku
    if params[:type] == 'product'
      flash[:alert] = 'Fetch Product From Heroku'
      Heroku.get_product
    end
  end

  post 'fetch_heroku' => 'admin#fetch_heroku'

Ne yapmam gerektiğinden emin değilim? CSRF'yi kapatmak kesinlikle işe yarar, ancak böyle bir API oluştururken benim hatam olduğunu düşünüyorum.

Yapmam gereken başka bir kurulum var mı?


5
API'ler için genellikle CSRF belirteç doğrulamasının kapatılması kabul edilir . Kullanıyorum protect_from_forgery with: :null_session.
dcestari

Yanıtlar:


110

Siteler arası istek sahteciliği (CSRF / XSRF), kötü amaçlı bir web sayfasının kullanıcıları, örneğin yer imleri, iç çerçeveler kullanarak veya sadece kullanıcıları kandıracak kadar görsel olarak benzer bir sayfa oluşturarak amaçlanmayan bir isteği gerçekleştirmeleri için kandırmasıdır.

Raylar CSRF koruması "klasik" web uygulamaları için yapılır - basit bir talep kendi web uygulamasından çıktığını güvence derecesi verir. CSRF belirteci, yalnızca sunucunuzun bildiği bir sır gibi çalışır - Rails rastgele bir belirteç oluşturur ve bunu oturumda saklar. Formlarınız belirteci gizli bir giriş yoluyla gönderir ve Rails, GET dışı herhangi bir isteğin oturumda depolananla eşleşen bir belirteç içerdiğini doğrular.

Ancak bir API genellikle tanımı gereği siteler arasıdır ve web uygulamanızdan daha fazlasında kullanılması amaçlanmıştır; bu, tüm CSRF kavramının tam olarak geçerli olmadığı anlamına gelir.

Bunun yerine, isteğin kendi uygulamanızdan değil, onaylanmış bir API istemcisinden geldiğini doğruladığınızdan, API isteklerini bir API anahtarı ve sırrı ile doğrulamak için jeton tabanlı bir strateji kullanmalısınız.

@Dcestari tarafından belirtildiği gibi CSRF'yi devre dışı bırakabilirsiniz:

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

Güncellenmiş. Rails 5'te şu --apiseçeneği kullanarak yalnızca API uygulamaları oluşturabilirsiniz :

rails new appname --api

CSRF ara yazılımını ve süper flouus olan diğer birçok bileşeni içermezler.


Teşekkürler,
CSRF'nin bir

4
bu, tüm API'lerin uygulamadan uygulamaya trafiğe hizmet ettiğini gösterir (tek bir ortağa benzersiz bir anahtar ve sır verilir). Bu senaryoda, sunucudan sunucuya iletişim gibi, bu cevap uygundur. ANCAK, çoğu web uygulaması geliştiricisinin kafasını karıştıran şey, sizin tarafınızdan kontrol edilen ve yazılan bir Javascript istemcisi için tek bir anahtar sırrı kullanmak İSTEMEZSİNİZ (bu, tüm istemcilere tek bir anahtar sırrını açığa çıkarır). Bunun yerine, CSRF jetonunu her istekle birlikte Rails'e geri gönderirseniz, Rail'in CSRF ve çerez oturum mekanizması, API'nizi kullanan Javascript uygulamaları için bile harika çalışır.
Jason FB

AJAX'ta bunu yapma şekliniz bu SO yazısında açıklanmıştır stackoverflow.com/questions/7203304/…
Jason FB

@JasonFB, javascript istemcileri ile tek bir sırrın çalışmadığı konusunda haklısınız. Ancak, diğer tarayıcı dışı istemciler tarafından da kullanılabilen bir API oluşturmayı düşünüyorsanız, oturumları ve Rails CSRF korumasını kullanmak hala sorunludur.
en fazla

CSRF'ye bir alternatif sağlar veya oluşturursanız, konuğum olun. Neyi değiştirdiğinizin nedenini bilin, böylece neyle değiştirmek için uygun olduğunu bilirsiniz. Açıkçası, şimdi kelime dağarcığımız bağlamsal hale geldi.
Jason FB

79

Boş oturum oluşturmayacak CSRF'yi kapatmanın başka bir yolu da eklemektir:

skip_before_action :verify_authenticity_token

Rails Denetleyicinizde. Bu, oturum bilgilerine hala erişebilmenizi sağlayacaktır.

Yine, bunu yalnızca API denetleyicilerinde veya CSRF korumasının pek uygulanmadığı diğer yerlerde yaptığınızdan emin olun.


1
Bu aynı protect_from_forgery except: [:my_method_name]mı?
Arnold Roa

19

Api.rubyonrails.org'da API denetleyicileri ile ilgili bir CSRF yapılandırması hakkında bilgi bulunmaktadır :

XML veya JSON isteklerinin de etkilendiğini ve bir API oluşturuyorsanız , sahtecilik koruma yöntemini ApplicationController(varsayılan olarak :) :exception:

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

Tipik olarak durumsuz olacak şekilde tasarlandıkları için API'ler için CSRF korumasını devre dışı bırakmak isteyebiliriz. Yani, istek API istemcisi oturumu Rails yerine sizin için yönetecektir.


4
Bu çok kafa karıştırıcı. protect_from_forgeryAPI'ler için hala gerekli olduğunu söyleyen kaynaklar ile bunun olmadığını söyleyen kaynaklar arasında tahminde bulunuyorum . Ya API, kullanıcı kimlik doğrulaması için oturum çerezini kullanan tek sayfalı bir uygulama içinse?
Wylliam Judd

CSRF mekanizması, Rails'in saldırı vektörüyle oturum tanımlama bilgilerini kullanarak başa çıkmanın yerleşik yoludur. Mekanizma, Rails oturum tanımlama bilgisinin yanında (aslında içinde) çalışırken denetleyicilerinizi korur. Protect_from_forgery olmadan veya kapatmadan veya üzerinde bir istisna ayarlamadan, Rails'e CSRF belirtecinden (oturum çerezinden alınan) bilgileri kullanarak bu eylemi korumamasını söylüyorsunuz.
Jason FB

5
Bence kafa karıştırıcı olan, Rails dokümantasyonu için "API" nin güvenilir, uzak ortaklardan (sitenizi ziyaret eden tüm web kullanıcılarından değil) API isteklerini alacak bir sunucudan sunucuya uygulama anlamına gelmesidir. Bu kişi için, hacklenemez güvenli bir mekanizma aracılığıyla benzersiz anahtar-gizli çiftleri verin. Birçok kişinin web uygulamanızı bir web istemcisi aracılığıyla yükleyeceği modern web uygulamaları için, sitenizi ziyaret eden her kişiyi benzersiz şekilde tanımlamak için bir oturum veya belirteç tabanlı mekanizma kullanmaya devam edersiniz. Bu nedenle, bunu yapmak için BAZI DİĞER mekanizmalar (Json Web belirteçleri, vb.) Kullanmıyorsanız, Rails'in yerleşik öğelerine bağlı kalın.
Jason FB

1
AJAX'ta bunu yapma şekliniz bu SO yazısında açıklanmıştır stackoverflow.com/questions/7203304/…
Jason FB

13

Rails 5'ten bu yana :: Base yerine :: API ile yeni bir sınıf da oluşturabilirsiniz :

class ApiController < ActionController::API
end

3

Örnek kontrolörün örnek eylemini hariç tutmak istiyorsanız

class TestController < ApplicationController
  protect_from_forgery :except => [:sample]

  def sample
     render json: @hogehoge
  end
end

Dışarıdan gelen talepleri sorunsuz bir şekilde işleme koyabilirsiniz.


0

Sorunun en basit çözümü, kontrolörünüzde standart şeyler yapmaktır veya doğrudan ApplicationController'a koyabilirsiniz.

class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true end


0

Yalnızca bir veya daha fazla denetleyici eylemi için (tüm denetleyici yerine) CSRF korumasını atlamak istiyorsanız, bunu deneyin

skip_before_action :verify_authenticity_token, only [:webhook, :index, :create]

[:webhook, :index, :create]Bu 3 eylem için kontrolü nerede atlayacaksınız, ancak hangisini atlamak isterseniz değiştirebilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.