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?

Author: Rimian, 2013-02-06

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
 274
Author: HungYuHei,
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.

 77
Author: Michelle Tilley,
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'
 28
Author: jsanders,
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')
 3
Author: Anton Orel,
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.

 1
Author: Blaine Hatab,
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
 1
Author: PaulL,
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ć.
 1
Author: Ruby Racer,
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!
 0
Author: Evgeniy Krokhmal,
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