rails - "UYARI: CSRF jeton gerçekliği doğrulanamıyor" json geliştirme istekleri için


82

CSRF belirtecini bir JSON isteğiyle iletilmek üzere nasıl alabilirim?

Güvenlik nedeniyle Rails'in tüm istek türlerinde (JSON / XML dahil) CSRF belirtecini kontrol ettiğini biliyorum .

Denetleyicimi skip_before_filter :verify_authenticity_tokentakabilirim, ancak CRSF korumasını kaybedebilirim (önerilmez :-)).

Bu benzer (hala kabul edilmeyen) cevap şunu öneriyor:

Jetonu ile alın <%= form_authenticity_token %>

Soru nasıl? Jetonu almak için sayfalarımdan herhangi birine ilk arama yapmam ve ardından Devise ile gerçek kimlik doğrulamamı yapmam gerekir mi? Ya da sunucumdan bir kereye mahsus alabileceğim ve daha sonra tutarlı bir şekilde kullanabileceğim bir bilgidir (sunucunun kendisinde manuel olarak değiştirene kadar)?

Yanıtlar:


127

DÜZENLE :

Rails 4'te şimdi @genkilabs'ın aşağıdaki yorumda önerdiklerini kullanıyorum:

protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

Bu, yerleşik güvenliği tamamen kapatmak yerine, CSRF belirteci olmadan sunucuya bir şey çarptığında var olabilecek herhangi bir oturumu sonlandırır.


skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }

Bu, uygun şekilde işaretlenmiş json gönderileri / koymaları için CSRF kontrolünü kapatır.

Örneğin, iOS'ta NSURLRequest'inize aşağıdakileri ayarlarken, burada "parametreler" parametrelerinizdir:


[request setHTTPMethod:@"POST"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"content-type"];

[request setValue:@"application/json" 
       forHTTPHeaderField:@"accept"];

[request setHTTPBody:[NSData dataWithBytes:[parameters UTF8String] 
                                            length:[parameters length]]];

3
bunu yaptığınızda, saldırgan biçimi 'json' olarak işaretliyorsa saldırıya maruz kalırsınız. Ve bu nedenle, tanım gereği Rails bir uyarı verir. Json'umun bir belirteci düzgün bir şekilde geçirebilmesini istiyorum, aksi takdirde günlüklerde uyarı olması yeterli.

21
saldırılara maruz kalıyorsunuz, bu yüzden filtreyi kapatırken başka bir güvenlik önlemi almanızı tavsiye ediyorlar. Tipik olarak API istekleri için, istek sahibi, istenen yöntemi çalıştırmadan önce doğrulayacağınız post verileriyle birlikte bir API anahtarı gönderir.
Ryan Crews

18
Raylar 4'te aşağıdakilere benzer bir şey yapabilirsiniz:protect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json' }
genkilabs

2
@genkilabs Bunu beğendim, 4 kullanıcı için yanıt vermek üzere eklendi, teşekkürler =]
Ryan Crews

1
Bunun Rails & iOS uygulamamda çalışmasını sağlamak için şimdi yaptığım iki şey: 1) Ruby'de eski ve yeni stil hash sözdizimini karıştırmamıza neden olacak herhangi bir neden görmedim, bu nedenle denetleyicimdeki kod şöyle görünüyor: protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }2) Bu soruyla alakasız ancak iOS'tan JSON POSTing konusuyla ilgili, kullanıyorum AFNetworkingve Rails parametreleri otomatik olarak sarmalamadığından, aşağıdakileri yaptım:manager.requestSerializer = [AFJSONRequestSerializer serializer];
mharper

18

Başarılı bir oturum açtıktan sonra, özel bir başlık kullanarak CSRF belirtecini gönderebilirsiniz.

Örneğin, bunu oturumlarınıza ekleyin # create:

response.headers['X-CSRF-Token'] = form_authenticity_token

CSRF jetonunu sağlayan örnek oturum açma yanıtı başlığı:

HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 35
Content-Type: application/json; charset=utf-8
Date: Mon, 22 Oct 2012 11:39:04 GMT
Etag: "9d719d3b9aabd413c3603e04e8a3933d"
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-10-12)
Set-Cookie: [cut for readability] 
X-Csrf-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=
X-Request-Id: 178746992d7aca928c876818fcdd4c96
X-Runtime: 0.169792
X-Ua-Compatible: IE=Edge

Bu Token, siz tekrar oturum açana kadar veya (API'niz aracılığıyla bunu destekliyorsanız oturumu kapatın) kadar geçerlidir. Müşteriniz, jetonu oturum açma yanıtı başlıklarından çıkarabilir ve depolayabilir. Ardından, her POST / PUT / DELETE isteği, X-CSRF-Token başlığını oturum açma sırasında alınan değerle ayarlamalıdır.

CSRF jetonlu örnek POST başlıkları:

POST /api/report HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Type: application/json; charset=utf-8
Cookie: [cut for readability]
Host: localhost:3000
User-Agent: HTTPie/0.3.0
X-CSRF-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=

Belgeler: form_authenticity_token


18

Gerçekten de en basit yol. Başlıkları değiştirmekle uğraşmayın.

Sahip olduğundan emin ol:

<%= csrf_meta_tag %>

senin içinde layouts/application.html.erb

Sadece böyle gizli bir giriş alanı yapın:

<input name="authenticity_token" 
       type="hidden" 
       value="<%= form_authenticity_token %>"/>

Veya bir jquery ajax gönderisi istiyorsanız:

$.ajax({     
    type: 'POST',
    url: "<%= someregistration_path %>",
    data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },                                                                                  
    error: function( xhr ){ 
      alert("ERROR ON SUBMIT");
    },
    success: function( data ){ 
      //data response can contain what we want here...
      console.log("SUCCESS, data="+data);
    }
});

Temel olarak json verilerinizi gönderdiğinizde, postverilere geçerli bir Authenticity_token alanı ekleyin ve uyarı kaybolmalıdır ...


IMHO, yalnızca kaydediciye bir uyarı koymakla kalmamalı, aynı zamanda varsayılan olarak geçerli bir csrf etiketi olmayan gönderileri de tamamen atmalıdır, sadece uyarıyı gönderir ve verileri gayet iyi gönderir ...
Walter Schreppers

Gizli özgünlük belirteci giriş alanını yapmanın daha kısa yolu = token_tag(nil)(sıfır önemlidir)
Yo Ludke

Rayların eski versiyonlarında etiket çoğul olarak biter. <% = csrf_meta_tags%>
cyonder

4

Bu hatayı şu şekilde çözdüm:

class ApplicationController < ActionController::Base
  protect_from_forgery
  skip_before_action :verify_authenticity_token, if: :json_request?

  protected

  def json_request?
    request.format.json?
  end
end

Kaynak: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html


Bunu yapmak isteyeceğinizden emin değilim - tarayıcılar JSON API'lerini kullanabilir.
Joe Van Dyk

Teşekkür ederim! Bu sorunu çözmek için hızlı (ve kirli) bir yola ihtiyacım vardı ve bu, başarmaya çalıştığım şey için yeterince iyi çalışabilir.
NerdyTherapist

Bağlantılı belge (artık Rails 5 için güncellendi) şu şekilde görünüyor: protect_from_forgery with: :exception, unless: -> { request.format.json? }ve benim için çalıştı. Teşekkürler.
akostadinov

1
Bu, sorunu ortadan kaldıran kontrolü devre dışı bırakır. Uygulama bunu devre dışı bırakacaksa, sahteciliğe karşı korumanın açık olmasının anlamı nedir?
jefflunt


2

Aşağıdakileri kullandım. Dahil mi kullanıyorsunuz? yani içerik türü application / json; charset = utf-8 ise, o zaman hala çalışıyor.

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

2

Bu cevap daha iyi.

Herhangi bir XMLHttpRequest göndermeden önce CSRF-TOKEN doğrulamasını fazladan çaba harcamadan (belirteç eklenir) tutabilirsiniz. JQuery yok, hiçbir şey kopyala / yapıştır ve yenileme yok.

Bu kodu eklemeniz yeterlidir.

(function() {
    var send = XMLHttpRequest.prototype.send,
        token = $('meta[name=csrf-token]').attr('content');
    XMLHttpRequest.prototype.send = function(data) {
        this.setRequestHeader('X-CSRF-Token', token);
        return send.apply(this, arguments);
    };
}());

1

Aşağıdaki Rails sürümüyle aynı sorunu yaşadım:
gem 'rails',: git => 'git: //github.com/rails/rails.git',: branch => '3-2-stable'

3.2.2'ye güncelledim ve şimdi her şey benim için iyi çalışıyor. :)
gem 'rayları', '3.2.2'


Önerin için teşekkürler. Denedim ama yine de aynı uyarıyı WARNING: Can't verify CSRF token authenticity

0

Bu gece aynı sorunla karşılaştım. Bunun olmasının nedeni, son csrf belirtecini oturum açtığınızda artık geçerli olmamasıdır. Yaptığım şey şuydu: $("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');uygulamanızda / views / devise / sessions / create.js.rb.

Şimdi geçerli bir csrf belirteci var :) Umarım yardımcı olur


0

Ayrıca geliştirme / test modu için.

protect_from_forgery with: :exception unless %w(development test).include? Rails.env

Bu uyarı, kullanmakta olduğunuz için :null_session, Rails 4.1'de hiçbir with:seçenek belirtilmemişse varsayılan olarak çalıştığını gösterir .

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