[ruby-on-rails] Rails : POST 요청을 할 때 CSRF 토큰 진위 여부를 확인할 수 없습니다.

POST request내 로컬 개발자에게 다음과 같이 만들고 싶습니다.

  HTTParty.post('http://localhost:3000/fetch_heroku',
                :body => {:type => 'product'},)

그러나 서버 콘솔에서보고합니다.

Started POST "/fetch_heroku" for 127.0.0.1 at 2016-02-03 23:33:39 +0800
  ActiveRecord::SchemaMigration Load (0.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by AdminController#fetch_heroku as */*
  Parameters: {"type"=>"product"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

여기 내 컨트롤러와 경로 설정이 있습니다. 매우 간단합니다.

  def fetch_heroku
    if params[:type] == 'product'
      flash[:alert] = 'Fetch Product From Heroku'
      Heroku.get_product
    end
  end

  post 'fetch_heroku' => 'admin#fetch_heroku'

무엇을해야하는지 잘 모르겠습니까? CSRF를 끄는 것은 확실히 효과가 있지만 그러한 API를 만들 때 내 실수라고 생각합니다.

수행해야하는 다른 설정이 있습니까?



답변

크로스 사이트 요청 위조 (CSRF / XSRF)는 악의적 인 웹 페이지가 북마크릿, iframe을 사용하거나 사용자를 속일 정도로 시각적으로 유사한 페이지를 만드는 등 의도하지 않은 요청을 수행하도록 사용자를 속이는 것입니다.

레일 CSRF 보호 “고전”웹 응용 프로그램을 위해 만들어 – 단순히 요청이 자신의 웹 응용 프로그램에서 유래 보증의 정도를 제공합니다. CSRF 토큰은 서버 만 알고있는 비밀처럼 작동합니다. Rails는 임의의 토큰을 생성하여 세션에 저장합니다. 양식은 숨겨진 입력을 통해 토큰을 보내고 Rails는 GET이 아닌 요청에 세션에 저장된 것과 일치하는 토큰이 포함되어 있는지 확인합니다.

그러나 API는 일반적으로 사이트 간 정의에 따라 웹 앱보다 더 많이 사용되는 것으로, CSRF의 전체 개념이 적용되지 않는다는 의미입니다.

대신 API 키와 시크릿으로 API 요청을 인증하는 토큰 기반 전략을 사용해야합니다. 요청이 자체 앱이 아닌 승인 된 API 클라이언트에서 온 것인지 확인하기 때문입니다.

@dcestari에서 지적한대로 CSRF를 비활성화 할 수 있습니다.

class ApiController < ActionController::Base
  protect_from_forgery with: :null_session
end

업데이트되었습니다. Rails 5에서는 다음 --api옵션 을 사용하여 API 전용 애플리케이션을 생성 할 수 있습니다 .

rails new appname --api

CSRF 미들웨어와 수퍼 플로우 인 다른 많은 구성 요소는 포함되지 않습니다.


답변

null 세션을 렌더링하지 않는 CSRF를 끄는 또 다른 방법은 다음을 추가하는 것입니다.

skip_before_action :verify_authenticity_token

Rails 컨트롤러에서. 이렇게하면 세션 정보에 계속 액세스 할 수 있습니다.

다시 말하지만 API 컨트롤러 또는 CSRF 보호가 적용되지 않는 다른 위치에서만이 작업을 수행해야합니다.


답변

api.rubyonrails.org의 API 컨트롤러와 관련된 CSRF 구성에 대한 관련 정보가 있습니다 .

XML 또는 JSON 요청도 영향을받으며 API 를 빌드하는 경우 다음 에서 위조 방지 방법을 변경해야합니다 ApplicationController(기본값 🙂 :exception.

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

일반적으로 상태 비 저장으로 설계되었으므로 API에 대한 CSRF 보호를 비활성화 할 수 있습니다. 즉, 요청 API 클라이언트가 Rails 대신 세션을 처리합니다.


답변

Rails 5부터 :: Base 대신 :: API 를 사용하여 새 클래스를 만들 수도 있습니다 .

class ApiController < ActionController::API
end


답변

샘플 컨트롤러의 샘플 동작을 제외하려는 경우

class TestController < ApplicationController
  protect_from_forgery :except => [:sample]

  def sample
     render json: @hogehoge
  end
end

외부의 요청을 문제없이 처리 할 수 ​​있습니다.


답변

문제에 대한 가장 간단한 해결책은 컨트롤러에서 표준 작업을 수행하거나 직접 ApplicationController에 넣을 수 있습니다.

class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, prepend: true
end


답변