Rails - "ВНИМАНИЕ: Невозможно проверить подлинность CSRF-токена" для запросов json
Как я могу получить токен CSRF для передачи с помощью запроса JSON?
Я знаю, что по соображениям безопасности Rails проверяет токен CSRF на всех типах запросов (включая JSON/XML).
Я мог бы установить мой контроллер skip_before_filter :verify_authenticity_token
, но я потерял бы защиту CRSF (не рекомендуется:-)).
Этот аналогичный (еще не принятый) ответ предлагает
Извлеките токен с помощью <%= form_authenticity_token %>
Вопрос в том, как? Мне нужно сделать первый вызов на любой из моих страниц, чтобы получить токен, а затем выполнить мою настоящую аутентификацию с помощью Devise? Или это одноразовая информация, которую я могу получить с моего сервера, а затем использовать последовательно (пока я не изменил ее вручную на самом сервере)?
Ответы
Ответ 1
ИЗМЕНИТЬ
В Rails 4 теперь я использую то, что @genkilabs предлагает в комментарии ниже:
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
Что вместо полного отключения встроенной безопасности уничтожает любой сеанс, который может существовать, когда что-то попадает на сервер без токена CSRF.
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
Это отключит проверку CSRF для json posts/puts, которые были должным образом помечены как таковые.
Например, при настройке iOS в ваш NSURLRequest, где "параметры" являются вашими параметрами:
[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]]];
Ответ 2
Вы можете отправить токен CSRF после успешного входа в систему с использованием настраиваемого заголовка.
Например, поместите это в свои сеансы # create:
response.headers['X-CSRF-Token'] = form_authenticity_token
Пример заголовка ответа для входа в систему, содержащего токен CSRF:
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
Этот токен действителен до тех пор, пока вы снова не войдете в систему или (выйдите из системы, если вы поддерживаете это через свой API).
Ваш клиент может извлекать и хранить токен из заголовков ответов входа в систему. Затем каждый запрос POST/PUT/DELETE должен установить заголовок X-CSRF-Token со значением, полученным во время входа.
Примеры заголовков POST с токеном CSRF:
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=
Документация: form_authenticity_token
Ответ 3
Простейший путь. Не беспокойтесь об изменении заголовков.
Убедитесь, что у вас есть:
<%= csrf_meta_tag %>
в layouts/application.html.erb
Просто введите скрытое поле ввода:
<input name="authenticity_token"
type="hidden"
value="<%= form_authenticity_token %>"/>
Или, если вам нужен jQuery пост ajax:
$.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);
}
});
В основном, когда вы публикуете данные json, просто добавьте действительное поле authenticity_token в данные post
, и предупреждение должно исчезнуть...
Ответ 4
Я решил эту ошибку следующим образом:
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
Источник:
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Ответ 5
Что беспокоит то, что в Rails 3.2.3 теперь мы получаем предупреждение CSRF в production.log, но сообщение не подведет! Я хочу, чтобы он потерпел неудачу, поскольку он защищает меня от атак. И вы можете добавить токен csrf с jquery перед фильтром btw:
http://jasoncodes.com/posts/rails-csrf-vulnerability
Ответ 6
Я использовал ниже. Использовать include? поэтому, если тип содержимого - application/json; charset = utf-8, то он все еще работает.
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.include? 'application/json' }
Ответ 7
Этот ответ лучше.
Вы должны сохранить проверку CSRF-TOKEN без каких-либо дополнительных усилий (добавляется токен) перед отправкой XMLHttpRequest. Нет JQuery, нет ничего, кроме как скопировать/вставить и обновить.
Просто добавьте этот код.
(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);
};
}());
Ответ 8
У меня была такая же проблема со следующей версией Rails:
gem 'rails',: git = > 'git://github.com/rails/rails.git',: branch = > '3-2-stable'
Я обновился до 3.2.2, и теперь все работает отлично.:)
gem 'rails', '3.2.2'
Ответ 9
Сегодня я столкнулся с тем же вопросом.
Причина, по которой происходит, заключается в том, что когда вы входите в последний токен csrf, больше не действует.
Я сделал это:
$("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');
в вашем приложении /views/devise/sessions/create.js.rb.
Теперь у него есть действительный csrf-токен:)
Я надеюсь, что это поможет
Ответ 10
Также для режима разработки/тестирования.
protect_from_forgery with: :exception unless %w(development test).include? Rails.env
Это предупреждение показывает, что вы используете :null_session
, в Rails 4.1 он работает по умолчанию, если не указано никаких опций with:
.
protect_from_forgery
Ответ 11
это не ошибка. Он должен быть проверен при каждом запросе, отличном от GET.
https://github.com/rails/rails/issues/3041