Szyny CSRF Ochrona + kątowa.js: ochrona przed fałszerstwem sprawia, że muszę się wylogować na poczcie
Jeśli opcja protect_from_forgery
jest wymieniona w application_controller, to mogę się zalogować i wykonać dowolne żądania GET, ale na pierwszym zapytaniu rails resetuje sesję, która mnie wylogowuje.
Wyłączyłem tymczasowo opcję protect_from_forgery
, ale chciałbym użyć jej z Angular.js. Jest na to jakiś sposób?
8 answers
Myślę, że czytanie CSRF-value z DOM nie jest dobrym rozwiązaniem, to tylko obejście.
Oto formularz dokumentu oficjalna strona angularJS http://docs.angularjs.org/api/ng.$http :
Ponieważ tylko JavaScript, który działa w Twojej domenie może odczytać plik cookie, Twój serwer może być pewien, że XHR pochodzi z JavaScript działającego w Twojej domenie.
Aby skorzystać z tego (Ochrona CSRF), Twój serwer musi ustawić token w JavaScript czytelny sesja plik cookie o nazwie XSRF-TOKEN na pierwszym żądaniu HTTP GET. Na kolejnych żądania non-GET serwer może sprawdzić, czy plik cookie pasuje X-XSRF-TOKEN HTTP header
Oto moje rozwiązanie oparte na tych instrukcjach:
Najpierw ustaw plik cookie:
# app/controllers/application_controller.rb
# Turn on request forgery protection
protect_from_forgery
after_action :set_csrf_cookie
def set_csrf_cookie
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
Następnie powinniśmy zweryfikować token przy każdym żądaniu non-GET.
Ponieważ Rails już zbudował podobną metodę, możemy po prostu nadpisać ją, aby dodać naszą logikę:
# app/controllers/application_controller.rb
protected
# In Rails 4.2 and above
def verified_request?
super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN'])
end
# In Rails 4.1 and below
def verified_request?
super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-19 13:15:00
Jeśli używasz domyślnej ochrony rails CSRF (<%= csrf_meta_tags %>
), możesz skonfigurować swój moduł kątowy w następujący sposób:
myAngularApp.config ["$httpProvider", ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
]
Lub, jeśli nie używasz CoffeeScript (co!?):
myAngularApp.config([
"$httpProvider", function($httpProvider) {
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
}
]);
Jeśli wolisz, możesz wysłać nagłówek tylko na żądania non-GET z czymś takim jak:
myAngularApp.config ["$httpProvider", ($httpProvider) ->
csrfToken = $('meta[name=csrf-token]').attr('content')
$httpProvider.defaults.headers.post['X-CSRF-Token'] = csrfToken
$httpProvider.defaults.headers.put['X-CSRF-Token'] = csrfToken
$httpProvider.defaults.headers.patch['X-CSRF-Token'] = csrfToken
$httpProvider.defaults.headers.delete['X-CSRF-Token'] = csrfToken
]
Sprawdź również odpowiedź HungYuHei , która obejmuje wszystkie bazy na serwerze, a nie na kliencie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:55
The angular_rails_csrf gem automatycznie dodaje obsługę wzorca opisanego w HungYuHei ' s answer do wszystkich kontrolerów:
# Gemfile
gem 'angular_rails_csrf'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:57
Odpowiedź, która łączy wszystkie poprzednie odpowiedzi i polega na tym, że używasz gem uwierzytelniania Devise
.
Po pierwsze, dodaj klejnot:
gem 'angular_rails_csrf'
Następnie dodaj rescue_from
Blok do application_controller.rb:
protect_from_forgery with: :exception
rescue_from ActionController::InvalidAuthenticityToken do |exception|
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
render text: 'Invalid authenticity token', status: :unprocessable_entity
end
I na koniec dodaj moduł interceptor do aplikacji angular.
# coffee script
app.factory 'csrfInterceptor', ['$q', '$injector', ($q, $injector) ->
responseError: (rejection) ->
if rejection.status == 422 && rejection.data == 'Invalid authenticity token'
deferred = $q.defer()
successCallback = (resp) ->
deferred.resolve(resp)
errorCallback = (resp) ->
deferred.reject(resp)
$http = $http || $injector.get('$http')
$http(rejection.config).then(successCallback, errorCallback)
return deferred.promise
$q.reject(rejection)
]
app.config ($httpProvider) ->
$httpProvider.interceptors.unshift('csrfInterceptor')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 16:00:12
Widziałem inne odpowiedzi i myślałem, że są świetne i dobrze przemyślane. Mam moją aplikację rails działającą z tym, co myślałem, że jest prostszym rozwiązaniem, więc pomyślałem, że się podzielę. Moja aplikacja rails pojawiła się z tym domyślnie,
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
Przeczytałem komentarze i wydawało mi się, że to jest to, co chcę użyć angular i uniknąć błędu csrf. Zmieniłem na to,
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session
end
I teraz to działa! Nie widzę powodu, dla którego miałoby to nie działać, ale chciałbym usłyszeć jakieś spostrzeżenia od innych plakaty.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-09 14:39:34
Użyłem treści z odpowiedzi HungYuHei w moim zgłoszeniu. Okazało się jednak, że mam do czynienia z kilkoma dodatkowymi problemami, niektóre z powodu mojego użycia Devise do uwierzytelniania, a niektóre z powodu domyślnej, że mam z moją aplikacją: {]}
protect_from_forgery with: :exception
Zwracam uwagę na powiązanepytanie o przepełnienie stosu i odpowiedzi tam , i napisałem znacznie bardziej obszernypost na blogu , który podsumowuje różne rozważania. Części tego rozwiązania, które są tu istotne są, w kontrolerze aplikacji:
protect_from_forgery with: :exception
after_filter :set_csrf_cookie_for_ng
def set_csrf_cookie_for_ng
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
end
rescue_from ActionController::InvalidAuthenticityToken do |exception|
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
render :error => 'Invalid authenticity token', {:status => :unprocessable_entity}
end
protected
def verified_request?
super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:57
Znalazłem bardzo szybkie włamanie do tego. Wszystko co musiałem zrobić to:
A. moim zdaniem inicjalizuję zmienną $scope
, która zawiera token, powiedzmy przed formularzem, lub jeszcze lepiej przy inicjalizacji kontrolera:
<div ng-controller="MyCtrl" ng-init="authenticity_token = '<%= form_authenticity_token %>'">
B. W moim kontrolerze AngularJS, przed zapisaniem nowego wpisu, dodaję token do hasha:
$scope.addEntry = ->
$scope.newEntry.authenticity_token = $scope.authenticity_token
entry = Entry.save($scope.newEntry)
$scope.entries.push(entry)
$scope.newEntry = {}
Nic więcej nie trzeba robić.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-30 22:21:47
angular
.module('corsInterceptor', ['ngCookies'])
.factory(
'corsInterceptor',
function ($cookies) {
return {
request: function(config) {
config.headers["X-XSRF-TOKEN"] = $cookies.get('XSRF-TOKEN');
return config;
}
};
}
);
Działa na stronie angularjs!Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 15:04:38