programing

Rails CSRF Protection + Angular.js: protect_from_forging으로 POST에서 로그아웃할 수 있습니다.

kingscode 2023. 4. 1. 14:15
반응형

Rails CSRF Protection + Angular.js: protect_from_forging으로 POST에서 로그아웃할 수 있습니다.

이 경우,protect_from_forgery옵션은 application_controller에 기재되어 있기 때문에 로그인하여 임의의 GET 요청을 실행할 수 있지만 Rails는 첫 번째 POST 요청 시 세션을 리셋하고 로그아웃합니다.

돌렸습니다.protect_from_forgery옵션은 일시적으로 꺼지지만 Angular.js와 함께 사용합니다.무슨 방법이 있을까요?

DOM에서 CSRF 값을 읽는 것은 좋은 해결책이 아니라 회피책이라고 생각합니다.

여기 각진 형태의 문서가 있습니다.JS 공식 웹사이트 http://docs.angularjs.org/api/ng.$http :

도메인에서 실행되는 JavaScript만 쿠키를 읽을 수 있으므로 XHR이 도메인에서 실행되는 JavaScript에서 가져온 것임을 서버에서 확인할 수 있습니다.

이 기능(CSRF Protection)을 이용하려면 서버는 첫 번째 HTTP GET 요구 시 XSRF-TOKEN이라는 JavaScript 판독 가능한 세션쿠키에 토큰을 설정해야 합니다.이후 비GET 요구에서는 서버는 쿠키가 X-XSRF-TOKEN HTTP 헤더와 일치하는지 확인할 수 있습니다.

이러한 순서에 근거한 솔루션을 다음에 나타냅니다.

먼저 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

다음으로 GET 이외의 요구마다 토큰을 확인해야 합니다.
Rails는 이미 유사한 방법으로 구축되었기 때문에 단순히 논리를 추가하기 위해 덮어쓸 수 있습니다.

# 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

기본 레일 CSRF 보호를 사용하는 경우(<%= csrf_meta_tags %>)는 다음과 같이 Angular 모듈을 설정할 수 있습니다.

myAngularApp.config ["$httpProvider", ($httpProvider) ->
  $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
]

또는 CoffeeScript를 사용하지 않는 경우(뭐라고요?)):

myAngularApp.config([
  "$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
  }
]);

필요에 따라서, 다음과 같은 비 GET 요구에 대해서만 헤더를 송신할 수 있습니다.

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
]

또, HungYuHei의 회답도 확인해 주세요.이 답변은 클라이언트가 아닌 서버상의 모든 베이스를 망라하고 있습니다.

angular_rails_csrf gem은 HungYuHei의 답변에서 설명된 패턴에 대한 지원을 모든 컨트롤러에 자동으로 추가합니다.

# Gemfile
gem 'angular_rails_csrf'

모든 이전 답변을 병합하고 사용 중인 답변에 의존합니다.Devise인증 보석

먼저 보석을 추가합니다.

gem 'angular_rails_csrf'

다음으로, 추가rescue_fromapplication_controller.block:

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

그리고 마지막으로 각진 앱에 인터셉터 모듈을 추가합니다.

# 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')

나는 다른 대답들을 보고 그들이 훌륭하고 잘 생각해냈다고 생각했다.레일즈 앱은 좀 더 심플한 솔루션이라고 생각했기 때문에 공유하려고 했습니다.제 레일 앱은 기본 설정으로 제공되었습니다.

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

댓글을 읽었는데, 각도에서 CSRF 에러를 피하고 싶은 것 같았습니다.이걸로 바꿨는데

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

그리고 이제 작동한다!이것이 효과가 없을 이유는 없지만, 다른 포스터에서 몇 가지 통찰력을 얻고 싶습니다.

Hung Yu Hei의 답변 내용을 응용 프로그램에 사용했습니다.다만, 인증에 Gand를 사용한 경우와 애플리케이션에 디폴트를 사용한 경우의 문제 등, 몇개의 추가의 문제가 있는 것을 알았습니다.

protect_from_forgery with: :exception

관련된 스택 오버플로우 질문과 답변에 주목하여 다양한 고려사항을 정리한 보다 장황한 블로그 투고를 작성했습니다.이 솔루션과 관련된 부분은 애플리케이션 컨트롤러에 있습니다.

  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

나는 이것에 대한 매우 빠른 해답을 찾았다.제가 해야 할 일은 다음과 같습니다.

엔 a.를 합니다.$scope예를 들어 토큰을 포함하는 변수(예: 형식 앞) 또는 컨트롤러 초기화가 더 우수합니다.

<div ng-controller="MyCtrl" ng-init="authenticity_token = '<%= form_authenticity_token %>'">

b. 나의 앵귤러에서JS 컨트롤러, 새 엔트리를 저장하기 전에 해시에 토큰을 추가합니다.

$scope.addEntry = ->
    $scope.newEntry.authenticity_token = $scope.authenticity_token 
    entry = Entry.save($scope.newEntry)
    $scope.entries.push(entry)
    $scope.newEntry = {}

더 이상 할 일이 없다.

 angular
  .module('corsInterceptor', ['ngCookies'])
  .factory(
    'corsInterceptor',
    function ($cookies) {
      return {
        request: function(config) {
          config.headers["X-XSRF-TOKEN"] = $cookies.get('XSRF-TOKEN');
          return config;
        }
      };
    }
  );

angularjs쪽에서 작동한다!

언급URL : https://stackoverflow.com/questions/14734243/rails-csrf-protection-angular-js-protect-from-forgery-makes-me-to-log-out-on

반응형