답변:
DOM에서 CSRF 값을 읽는 것이 좋은 해결책은 아니라고 생각합니다.
다음은 angularJS 공식 웹 사이트 http://docs.angularjs.org/api/ng.$http 의 문서 양식입니다 .
도메인에서 실행되는 JavaScript만이 쿠키를 읽을 수 있으므로 서버는 XHR이 도메인에서 실행되는 JavaScript에서 온 것임을 확신 할 수 있습니다.
이를 활용하려면 (CSRF Protection) 서버가 첫 번째 HTTP GET 요청에서 XSRF-TOKEN이라는 JavaScript 읽기 가능 세션 쿠키에 토큰을 설정해야합니다. 후속 비 GET 요청에서 서버는 쿠키가 X-XSRF-TOKEN HTTP 헤더와 일치하는지 확인할 수 있습니다.
다음은 해당 지침을 기반으로 한 솔루션입니다.
먼저 쿠키를 설정하십시오.
# 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
기본 Rails CSRF 보호 ( <%= csrf_meta_tags %>
)를 사용하는 경우 다음 과 같이 Angular 모듈을 구성 할 수 있습니다.
myAngularApp.config ["$httpProvider", ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
]
또는 CoffeeScript를 사용하지 않는 경우 (what !?) :
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의 답변 을 확인하십시오.이 답변 은 클라이언트가 아닌 서버의 모든 기반을 포괄합니다.
<%= csrf_meta_tags %>
. 나는 언급 protect_from_forgery
만으로 충분하다고 생각했다 . 무엇을해야합니까? 기본 문서는 일반 HTML이어야합니다 (여기서는 내가 선택한 문서가 아닙니다).
protect_from_forgery
"내 JavaScript 코드가 Ajax 요청 X-CSRF-Token
을 할 때 현재 CSRF 토큰에 해당하는 헤더 를 보내겠다"고 말하는 것을 사용 합니다 . 이 토큰을 얻기 위해 Rails는 토큰을 DOM에 삽입하고 <%= csrf_meta_token %>
Ajax 요청을 할 때마다 jQuery로 메타 태그의 내용을 가져옵니다 (기본 Rails 3 UJS 드라이버가이를 수행함). ERB를 사용하지 않는 경우 현재 토큰을 Rails에서 페이지 및 / 또는 JavaScript로 가져올 수있는 방법이 없으므로이 protect_from_forgery
방식으로 사용할 수 없습니다 .
csrf_meta_tags
서버가 응답을 생성 할 때마다 이러한 태그가 이전 태그와 다를 때마다 수신한다고 생각했습니다 . 따라서이 태그는 각 요청마다 고유합니다. 문제는 애플리케이션이 어떻게 AJAX 요청에 대해 이러한 태그를 수신합니까 (각도없이)? jQuery POST 요청에 protect_from_forgery를 사용 했으며이 CSRF 토큰을 얻는 데 신경 쓰지 않았습니다. 어떻게?
jQuery.ajaxPrefilter
다음과 같이이 : github.com/indirect/jquery-rails/blob/c1eb6ae/vendor/assets/... 이 파일을 정독 할 수 있으며 필요없이 농구 레일을 통해 이동 모두가 거의 작동하도록 참조 그것에 대해 걱정하십시오.
put
및 post
대신에 common
? 로부터 레일 보안 가이드 :The solution to this is including a security token in non-GET requests
angular_rails_csrf의 보석은 자동으로 설명 된 패턴에 대한 지원을 추가 HungYuHei의 대답은 모든 컨트롤러 :
# Gemfile
gem 'angular_rails_csrf'
angular_rails_csrf
gem은 Rails 5에서 작동하지 않습니다. 그러나 CSRF 메타 태그의 값으로 Angular 요청 헤더를 구성하면 작동합니다!
모든 이전 답변을 병합하고 Devise
인증 gem을 사용하고있는 답변 입니다.
우선, 보석을 추가하십시오 :
gem 'angular_rails_csrf'
다음 rescue_from
으로 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
마지막으로 인터셉터 모듈을 각도 앱에 추가하십시오.
# 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')
$injector
직접 주사 하는 대신 주사 하는 이유는 무엇 $http
입니까?
나는 다른 답을 보았고 그들이 훌륭하고 잘 생각했다고 생각했습니다. 나는 더 간단한 해결책이라고 생각한 것과 함께 레일 응용 프로그램을 작동 시켜서 공유 할 것이라고 생각했습니다. 내 Rails 앱은 기본적으로 제공됩니다.
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
그리고 지금 작동합니다! 왜 이것이 작동하지 않는지 알 수 없지만 다른 포스터의 통찰력을 듣고 싶습니다.
내 응용 프로그램에서 HungYuHei의 답변 내용을 사용했습니다. 그러나 인증을 위해 Devise를 사용하고 일부는 내 응용 프로그램에서 얻은 기본값 때문에 몇 가지 추가 문제를 처리하고 있음을 발견했습니다.
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
나는 이것에 대한 매우 빠른 해킹을 발견했다. 내가해야 할 일은 다음과 같습니다.
ㅏ. 내 관점에서, 나는 $scope
토큰을 포함 하는 변수를 초기화 하거나, 양식 전에 말하거나 심지어 컨트롤러 초기화에 더 잘합시다.
<div ng-controller="MyCtrl" ng-init="authenticity_token = '<%= form_authenticity_token %>'">
비. AngularJS 컨트롤러에서 새 항목을 저장하기 전에 해시에 토큰을 추가합니다.
$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 측에서 일하고 있습니다!