[RUBY-ON-RAILS] 레일 고안 인증, CSRF 문제
RUBY-ON-RAILS레일 고안 인증, CSRF 문제
나는 레일을 사용하여 그을음 페이지 응용 프로그램을하고 있어요. 유증 컨트롤러와 로그 아웃 할 때 Ajax를 사용하여 호출됩니다. 내가 갖는 문제는 내가 1) 2에 로그인 할 때) 다시 일을하지 않습니다에 다음 서명 로그 아웃이다.
나는 내가 로그 아웃 할 때 리셋을 얻을 수있는 토큰 CSRF에 관한 생각하고 한 페이지, 따라서 세션을 재설정 XHR 요청에서 전송되는 토큰 이전 CSRF 이후 (그렇지 AFAIK해야하지만).
이 워크 플로 더 구체적으로 :
모든 단서가 대단히 감사합니다! 나는 더 이상 세부 사항을 추가 할 수 있는지 알려주세요.
해결법
-
==============================
1.짐보는 "왜"문제 뒤에 당신이로 실행중인 설명하는 멋진 일을했다. 이 문제를 해결하기 위해 취할 수있는 방법은 두 가지가 있습니다 :
짐보는 "왜"문제 뒤에 당신이로 실행중인 설명하는 멋진 일을했다. 이 문제를 해결하기 위해 취할 수있는 방법은 두 가지가 있습니다 :
-
==============================
2.난 그냥뿐만 아니라이 문제로 실행했습니다. 여기서 살펴 봐야 할 것들이 많다.
난 그냥뿐만 아니라이 문제로 실행했습니다. 여기서 살펴 봐야 할 것들이 많다.
TL; DR - 실패하는 이유는 서버 세션과 관련된 토큰 CSRF는 (당신이 로그인 또는 로그 아웃하고 있는지 서버 세션있어)이다. CSRF 토큰은 DOM의 모든 페이지로드에 페이지를 포함되어 있습니다. 로그 아웃, 세션이 재설정되고 더 CSRF 토큰이 없습니다. 일반적으로, 당신이 아약스를 사용하고 있기 때문에 당신에게 새로운 CSRF 토큰을 제공하지만, 다른 페이지 / 액션에 로그 아웃 리디렉션, 당신은 수동으로 수행해야합니다.
자세한 설명 당신은 가장 가능성 (이것이 내가 생각하는 매우 일반적이다) 다른 컨트롤러의 모든 상속있는 당신의 ApplicationController.rb 파일에 protect_from_forgery 세트를 가지고있다. protect_from_forgery 수행하는 모든 비 GET은 HTML / 자바 스크립트 요청에 검사를 CSRF. 유증 로그인이 POST이기 때문에, 그것은 CSRF 검사를 수행합니다. CSRF 확인은 서버가 (올바른 / 원하는 동작입니다) 공격의 가정하기 때문에 사용자의 현재 세션, 즉, 사용자가 로그 아웃, 클리어에 실패합니다.
A가 상태를 로그 아웃 당신이 시작하고 가정 그래서, 당신은 새로운 페이지로드를 수행하고 다시는 페이지를 다시로드 :
업데이트 : 8/14 고안 로그 아웃, 당신에게 로그 아웃 당신에게 새로운 CSRF 토큰을 제공 한 후 일반적으로 발생하는 리디렉션을 새로운 CSRF 토큰을 제공하지 않습니다.
-
==============================
3.내 대답은 그러나 나는 유증을 사용하고, @Jimbo 및 @Sija 모두에서 많이 차용 / 컨벤션 레일 CSRF 보호 + Angular.js에서 제안 AngularJS와 : protect_from_forgery가 POST에 로그 아웃 나를 만들고, 내 블로그에 조금 정교 때 원래 이런 짓을. 이 CSRF에 대한 설정 쿠키 응용 프로그램 컨트롤러의 방법이있다 :
내 대답은 그러나 나는 유증을 사용하고, @Jimbo 및 @Sija 모두에서 많이 차용 / 컨벤션 레일 CSRF 보호 + Angular.js에서 제안 AngularJS와 : protect_from_forgery가 POST에 로그 아웃 나를 만들고, 내 블로그에 조금 정교 때 원래 이런 짓을. 이 CSRF에 대한 설정 쿠키 응용 프로그램 컨트롤러의 방법이있다 :
after_filter :set_csrf_cookie_for_ng def set_csrf_cookie_for_ng cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? end
내가 Sija의 형식 @ 사용하지만, 저를주고, 그 이전 SO 솔루션의 코드를 사용하고 그래서 :
class SessionsController < Devise::SessionsController after_filter :set_csrf_headers, only: [:create, :destroy] protected def set_csrf_headers cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? end end
그것을 해결하기 위해 나에게 몇 분 걸렸다 때문에 완성도를 들어, 나는 또한 당신이 세션 컨트롤러를 무시했다고 선언하기 위해 설정 / routes.rb 수정할 필요가 있습니다. 뭔가 같은 :
devise_for :users, :controllers => {sessions: 'sessions'}
이것은 또한 다른 사람에게 흥미로운 일이 될 수도 있습니다 내 응용 프로그램에서 수행 한 것을 큰 CSRF 정리의 일부였다. 블로그 포스트는 여기에, 다른 변경 사항은 다음과 같습니다
일이 동기화의 나갈 경우 응용 프로그램이 아니라 명확한 쿠키 필요로하는 사용자에 비해, 자체 해결된다는 것을 의미합니다 ActionController :: InvalidAuthenticityToken에서 구출. 상황이 레일에 서서 나는 응용 프로그램 컨트롤러로 디폴트 될 것이라고 생각 :
protect_from_forgery with: :exception
그 상황에서는, 당신은 필요 :
rescue_from ActionController::InvalidAuthenticityToken do |exception| cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? render :error => 'invalid token', {:status => :unprocessable_entity} end
당신이 cookie_store보다는 active_record_store 사용을 고려하고, 병렬 발행주의해야 짧은 - 나는 또한 경쟁 조건 내가 블로그 게시물에서 더에 댓글을 한 유증에 timeoutable 모듈, 일부 상호 작용 약간의 슬픔을 했어 sign_in 및 sign_out 행동 근처에 요청.
-
==============================
4.이것은 필자의 의견입니다 :
이것은 필자의 의견입니다 :
class SessionsController < Devise::SessionsController after_filter :set_csrf_headers, only: [:create, :destroy] respond_to :json protected def set_csrf_headers if request.xhr? response.headers['X-CSRF-Param'] = request_forgery_protection_token response.headers['X-CSRF-Token'] = form_authenticity_token end end end
그리고 클라이언트 측 :
$(document).ajaxComplete(function(event, xhr, settings) { var csrf_param = xhr.getResponseHeader('X-CSRF-Param'); var csrf_token = xhr.getResponseHeader('X-CSRF-Token'); if (csrf_param) { $('meta[name="csrf-param"]').attr('content', csrf_param); } if (csrf_token) { $('meta[name="csrf-token"]').attr('content', csrf_token); } });
당신의 CSRF 메타 태그는 아약스 요청을 통해 X-CSRF 토큰 또는 X-CSRF - 파람 헤더를 반환 할 때마다 계속 업데이트됩니다 어느.
-
==============================
5.교도소 소스에 파고 후, 나는 CSRF 토큰이 서명 아웃 사이에 유지되도록 false로 sign_out_all_scopes을 설정하면, 전체 세션을 삭제에서 소장을 중지 것으로 나타났습니다.
교도소 소스에 파고 후, 나는 CSRF 토큰이 서명 아웃 사이에 유지되도록 false로 sign_out_all_scopes을 설정하면, 전체 세션을 삭제에서 소장을 중지 것으로 나타났습니다.
유증 발행 테커에 관련 토론 : https://github.com/plataformatec/devise/issues/2200
-
==============================
6.난 그냥 내 레이아웃 파일이 추가하고 일했다
난 그냥 내 레이아웃 파일이 추가하고 일했다
<%= csrf_meta_tag %> <%= javascript_tag do %> jQuery(document).ajaxSend(function(e, xhr, options) { var token = jQuery("meta[name='csrf-token']").attr("content"); xhr.setRequestHeader("X-CSRF-Token", token); }); <% end %>
-
==============================
7.당신이 당신의 application.js 파일이 포함 여부 확인
당신이 당신의 application.js 파일이 포함 여부 확인
이유 존재는 자동으로 기본적으로 모든 Ajax 요청에 토큰 CSRF를 설정 보석 JQuery와 - 레일입니다 두를 필요
-
==============================
8.내 경우에 사용자가 로그인 한 후, 나는 사용자의 메뉴를 다시 그릴 필요가 있었다. 즉 일,하지만 난, 같은 섹션에 (물론, 페이지를 새로 고치지 않고) 서버에 대한 모든 요청에 CSRF의 인증 오류를 얻었다. 내가 JS보기를 렌더링하는 데 필요하기 때문에 위의 솔루션이 작동되지 않았습니다.
내 경우에 사용자가 로그인 한 후, 나는 사용자의 메뉴를 다시 그릴 필요가 있었다. 즉 일,하지만 난, 같은 섹션에 (물론, 페이지를 새로 고치지 않고) 서버에 대한 모든 요청에 CSRF의 인증 오류를 얻었다. 내가 JS보기를 렌더링하는 데 필요하기 때문에 위의 솔루션이 작동되지 않았습니다.
내가 한 일은이 사용 고안입니다 :
응용 프로그램 / 컨트롤러 / sessions_controller.rb
class SessionsController < Devise::SessionsController respond_to :json # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? if request.format.json? markup = render_to_string :template => "devise/sessions/popup_login", :layout => false render :json => { :data => markup }.to_json else respond_with(resource, serialize_options(resource)) end end # POST /resource/sign_in def create if request.format.json? self.resource = warden.authenticate(auth_options) if resource.nil? return render json: {status: 'error', message: 'invalid username or password'} end sign_in(resource_name, resource) render json: {status: 'success', message: '¡User authenticated!'} else self.resource = warden.authenticate!(auth_options) set_flash_message(:notice, :signed_in) sign_in(resource_name, resource) yield resource if block_given? respond_with resource, location: after_sign_in_path_for(resource) end end end
그 후 나는 메뉴를 묘화 제어부 # 1 액션 요청했다. 그리고 자바 스크립트에서, 나는 X-CSRF - 파람 및 X-CSRF 토큰을 수정 :
응용 프로그램 / 뷰 / 유틸리티 / redraw_user_menu.js.erb
$('.js-user-menu').html(''); $('.js-user-menu').append('<%= escape_javascript(render partial: 'shared/user_name_and_icon') %>'); $('meta[name="csrf-param"]').attr('content', '<%= request_forgery_protection_token.to_s %>'); $('meta[name="csrf-token"]').attr('content', '<%= form_authenticity_token %>');
나는 그것이 같은 JS 상황에서 누군가를 위해 유용 희망 :)
-
==============================
9.내 상황은 더 간단했다. 사람이 양식 화면에 앉아 자신의 세션 시간 초과 (고안 timeoutable 세션 시간 초과) 경우, 일반적으로 그들은 그 시점에 제출 치면, 유증이 다시 반송 것 : 내 경우에는, 모든 나는이되었다하고 싶어 로그인 화면으로 이동합니다. 그들은 모든 형태의 데이터가 손실 때문에 글쎄, 나는 그것을 원하지 않았다. 나는 양식, 아약스, 사용자가 더 이상 로그인하면 결정하지 않는 컨트롤러를 호출 제출 잡기 위해 자바 스크립트를 사용하고 그런 경우가 있다면 나는 그들이 자신의 암호를 다시 입력 양식을 올려, 나는 (컨트롤러에 bypass_sign_in)을 재 인증 Ajax 호출을 사용하여. 그런 다음 원래의 형태는 계속 허용됩니다 제출합니다.
내 상황은 더 간단했다. 사람이 양식 화면에 앉아 자신의 세션 시간 초과 (고안 timeoutable 세션 시간 초과) 경우, 일반적으로 그들은 그 시점에 제출 치면, 유증이 다시 반송 것 : 내 경우에는, 모든 나는이되었다하고 싶어 로그인 화면으로 이동합니다. 그들은 모든 형태의 데이터가 손실 때문에 글쎄, 나는 그것을 원하지 않았다. 나는 양식, 아약스, 사용자가 더 이상 로그인하면 결정하지 않는 컨트롤러를 호출 제출 잡기 위해 자바 스크립트를 사용하고 그런 경우가 있다면 나는 그들이 자신의 암호를 다시 입력 양식을 올려, 나는 (컨트롤러에 bypass_sign_in)을 재 인증 Ajax 호출을 사용하여. 그런 다음 원래의 형태는 계속 허용됩니다 제출합니다.
내가 protect_from_forgery을 추가 할 때까지 완벽하게 작동했다.
난 그냥 새로운 CSRF 토큰에 인스턴스 변수를 설정합니다 (bypass_sign_in)에서 사용자의 뒷면에 서명 어디 그래서, 모두 내가 필요로 위의 답변 덕분에 정말 내 컨트롤러에 있었다 :
@new_csrf_token = form_authenticity_token
그리고 렌더링 된 .js.erb에 (다시 보낸, 이것은 XHR 호출이었다)
$('meta[name="csrf-token"]').attr('content', '<%= @new_csrf_token %>'); $('input[type="hidden"][name="authenticity_token"]').val('<%= @new_csrf_token %>');
짜잔. 따라서 갱신 및되지 않은 내 양식 페이지는, 지금은 내 사용자 로그인에서 가져온 새로운 세션에서 새 토큰을 가지고, 기존의 토큰으로 붙어 있었다.
-
==============================
10.@ sixty4bit의 코멘트에 회신; 이 오류로 실행하면 :
@ sixty4bit의 코멘트에 회신; 이 오류로 실행하면 :
Unexpected error while processing request: undefined method each for :authenticity_token:Symbol`
바꾸다
response.headers['X-CSRF-Param'] = request_forgery_protection_token
와
response.headers['X-CSRF-Param'] = request_forgery_protection_token.to_s
from https://stackoverflow.com/questions/11845500/rails-devise-authentication-csrf-issue by cc-by-sa and MIT license
'RUBY-ON-RAILS' 카테고리의 다른 글
[RUBY-ON-RAILS] 갑자기 작동하지 드롭 다운 부트 스트랩 트위터 (0) | 2020.02.15 |
---|---|
[RUBY-ON-RAILS] PG (0.17.1)를 설치하는 동안 오류가 발생하고, Bundler를 계속할 수 없습니다 (0) | 2020.02.15 |
[RUBY-ON-RAILS] 프로필에 어떤 도구를 당신이 권장합니까 앱 레일? [닫은] (0) | 2020.02.15 |
[RUBY-ON-RAILS] 의 nginx / 여객에서 "불완전한 응답은 응용 프로그램에서받은" (0) | 2020.02.15 |
[RUBY-ON-RAILS] 레일 - LINK_TO에 매개 변수를 전달 (0) | 2020.02.15 |