รางของแท้ 4 โทเค็น


198

ฉันกำลังทำงานกับแอพ Rails 4 ใหม่ (ใน Ruby 2.0.0-p0) เมื่อฉันพบปัญหาโทเค็นของแท้

ในขณะที่เขียนตัวควบคุมที่ตอบสนองต่อ JSON (โดยใช้respond_toวิธีการเรียน) ผมได้ไปcreateดำเนินการผมเริ่มได้รับข้อยกเว้นเมื่อฉันพยายามที่จะสร้างการบันทึกการใช้ActionController::InvalidAuthenticityTokencurl

ฉันแน่ใจว่าฉันตั้งค่า-H "Content-Type: application/json"และฉันตั้งค่าข้อมูลด้วย-d "<my data here>"แต่ก็ยังไม่มีโชค

ฉันพยายามเขียนคอนโทรลเลอร์เดียวกันโดยใช้ Rails 3.2 (บน Ruby 1.9.3) และฉันไม่มีปัญหาโทเค็นของแท้ใด ๆ ฉันค้นหารอบ ๆ และเห็นว่ามีการเปลี่ยนแปลงบางอย่างเกี่ยวกับโทเค็นของแท้ใน Rails 4 จากสิ่งที่ฉันเข้าใจพวกเขาจะไม่ถูกแทรกโดยอัตโนมัติในแบบฟอร์มอีกต่อไป? ฉันคิดว่านี่จะส่งผลกระทบต่อประเภทเนื้อหาที่ไม่ใช่ HTML

มีวิธีใดบ้างที่จะหลีกเลี่ยงสิ่งนี้ได้โดยไม่ต้องร้องขอฟอร์ม HTML แย่งโทเค็นของแท้จากนั้นจึงส่งคำขออื่นด้วยโทเค็นนั้น หรือฉันขาดสิ่งที่เห็นได้อย่างสมบูรณ์

แก้ไข:ฉันเพิ่งลองสร้างสถิติใหม่ในแอพ Rails 4 ใหม่โดยใช้โครงโดยไม่ต้องเปลี่ยนอะไรเลยและฉันพบปัญหาเดียวกันดังนั้นฉันคิดว่าไม่ใช่สิ่งที่ฉันทำ

คำตอบ:


277

ฉันคิดว่าฉันคิดออก ฉันเปลี่ยนค่าเริ่มต้น (ใหม่)

protect_from_forgery with: :exception

ถึง

protect_from_forgery with: :null_session

ApplicationControllerตามความคิดเห็นใน

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

คุณสามารถเห็นความแตกต่างโดยดูที่แหล่งที่มาrequest_forgery_protecton.rbหรือเฉพาะเจาะจงมากยิ่งขึ้นบรรทัดต่อไปนี้:

ในRails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

ในRails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

ซึ่งจะเรียกสิ่งต่อไปนี้ :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end

20
คุณสามารถลบ: พร้อมตัวเลือกทั้งหมดเข้าด้วยกัน: null_session เป็นค่าเริ่มต้น: api.rubyonrails.org/classes/ActionController/…
Casey

6
มีวิธีใช้ข้อยกเว้นสำหรับการโทรที่ไม่ใช่ JSON และเซสชันว่างสำหรับการโทร JSON (การโทร API หรือไม่)?
James McMahon

@JamesMcMahon คุณอาจจะสามารถเขียนของคุณเองbefore_actionที่ตรวจสอบรูปแบบและตรวจสอบว่ามีการตรวจสอบคำขอ ฉันไม่ทราบวิธีการกำหนดเงื่อนไข
alexcoco

1
ใน Rails 4.1.6 ฉันต้องระบุskip_before_action :verify_authenticity_tokenตัวควบคุมแอปพลิเคชัน API ของฉันเพื่อให้สามารถใช้งานได้
Waseem

1
คุณไม่จำเป็นต้องปิดการใช้งาน:verify_authenticy_tokenอีกใน Rails 4.2 มันเป็นค่าเริ่มต้น:null_sessionซึ่งตามชื่อหมายถึงเพียงแค่ให้คุณร้องขอโดยไม่ต้องเซสชั่น คุณสามารถยืนยันคำขอผ่านคีย์ API แทน
lobati

72

แทนที่จะปิดการป้องกัน csrf คุณควรเพิ่มบรรทัดของรหัสต่อไปนี้ลงในแบบฟอร์ม

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

และถ้าคุณใช้ form_for หรือ form_tag เพื่อสร้างแบบฟอร์มมันจะเพิ่มโค้ดด้านบนลงในฟอร์มโดยอัตโนมัติ


9
นี่เป็นคำแนะนำที่ดีหากคุณกำลังสร้างแบบฟอร์ม แต่คำถามนี้หมายถึงการโทรผ่าน API โดยใช้ JSON
James McMahon

1
ขอบคุณแม้ว่านี่จะตอบคำถามที่ฉันมีเกี่ยวกับการเขียนโค้ดด้วยมือขณะใช้แฮนด์บาร์!
David Routen

70

การเพิ่มบรรทัดต่อไปนี้ในรูปแบบที่ทำงานสำหรับฉัน:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

12
ไม่สามารถใช้กับการเรียก api ได้จริงๆ
courtimas

2
ในกรณีของฉันฉันใช้ Rails4 ฉันสามารถส่งแบบฟอร์มโดยคลิกที่ปุ่มส่ง แต่ถ้าฉันส่งแบบฟอร์มด้วยรหัส JS ข้อผิดพลาดนี้จะเกิดขึ้น และคำตอบนี้แก้ไขปัญหาให้ฉัน
Chris.Zou

2
สำหรับแอพที่ใช้ Rails 4.0.8 ของฉันมันก็เพียงพอที่จะเขียน=token_tag nilหรือ (ใน. erb)<%= token_tag nil %>
jmarceli

1
ดูเหมือนว่าคุณจะปิดใช้งานการรับรองความถูกต้องโดยการตั้งโทเค็นเป็นศูนย์หรือไม่
Carlos

การทำเช่นนี้ปลอดภัยไหม
Angel Garcia

33

ฉันไม่คิดว่าเป็นการดีที่จะปิดการป้องกัน CSRF โดยทั่วไปตราบใดที่คุณไม่ได้ใช้ API เพียงอย่างเดียว

เมื่อดูที่เอกสารประกอบ Rails 4 API สำหรับActionControllerฉันพบว่าคุณสามารถปิดการป้องกันการปลอมแปลงในแต่ละคอนโทรลเลอร์หรือต่อเมธอด

ตัวอย่างเช่นการปิดการป้องกัน CSRF สำหรับวิธีการที่คุณสามารถใช้ได้

class FooController < ApplicationController
  protect_from_forgery except: :index

สิ่งนี้ทำเพื่อฉันใน Rails 4 - เกิดข้อผิดพลาดหลังจากพยายามลบ ^^
zero_cool

9

มาข้ามปัญหาเดียวกัน แก้ไขโดยเพิ่มลงในคอนโทรลเลอร์ของฉัน:

      skip_before_filter :verify_authenticity_token, if: :json_request?

วิธีที่ไม่ได้กำหนด `json_request? ' สำหรับ # <SettingsController: 0x000000030a54a8> ความคิดใด ๆ
Deano

คุณต้องกำหนดวิธีการเช่น: def json_request? request.format.json? สิ้น
ใจ Kumar Rajput


4

เอกสารอย่างเป็นทางการนี้ - พูดถึงวิธีปิดการป้องกันการปลอมแปลงสำหรับ API อย่างถูกต้อง http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html


1
นั่นเป็นความจริง แต่คำตอบนั้นมาจากปี 2013 และสิ่งต่าง ๆ ก็เปลี่ยนไป และในขณะที่คำตอบที่ได้รับการยอมรับอย่างเป็นทางการของคุณนั้นดี - ลิงค์ของฉันให้ภาพรวมเชิงลึกของเรื่องได้ดีขึ้น
konung


2

คุณสมบัติเหล่านี้ถูกเพิ่มเข้ามาเพื่อความปลอดภัยและการป้องกันการปลอมแปลง
อย่างไรก็ตามเพื่อตอบคำถามของคุณนี่คืออินพุตบางส่วน คุณสามารถเพิ่มบรรทัดเหล่านี้หลังจากชื่อตัวควบคุมของคุณ

เช่นนั้น

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

นี่คือบางบรรทัดสำหรับ Rails รุ่นต่างๆ

ราง 3

skip_before_filter: Verify_authenticity_token

ราง 4 :

skip_before_action: Verify_authenticity_token


คุณควรตั้งใจจะปิดใช้งานคุณลักษณะการรักษาความปลอดภัยสำหรับทุกขั้นตอนการควบคุมคุณสามารถเปลี่ยนค่าของprotect_from_forgeryไป: null_sessionในไฟล์ application_controller.rb ของคุณ

เช่นนั้น

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

1

หากคุณกำลังใช้ jQuery กับทางรถไฟโปรดระวังการอนุญาตให้เข้าสู่วิธีการโดยไม่ต้องตรวจสอบโทเค็นของแท้

jquery-ujs สามารถจัดการโทเค็นให้คุณได้

คุณควรจะมีมันเป็นส่วนหนึ่งของอัญมณี jquery-rails แต่คุณอาจจำเป็นต้องรวมมันไว้ใน application.js ด้วย

//= require jquery_ujs

นั่นคือทั้งหมดที่คุณต้องการ - การโทร ajax ของคุณควรใช้งานได้แล้ว

สำหรับข้อมูลเพิ่มเติมโปรดดูที่: https://github.com/rails/jquery-ujs



0

เมื่อคุณกำหนดรูปแบบ html ของคุณเองคุณจะต้องรวมสตริงโทเค็นการตรวจสอบความถูกต้องซึ่งจะถูกส่งไปยังตัวควบคุมด้วยเหตุผลด้านความปลอดภัย หากคุณใช้ตัวช่วยสร้างรูปแบบรางเพื่อสร้างโทเค็นของแท้จะถูกเพิ่มไปยังแบบฟอร์มดังต่อไปนี้

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
  </div>
    ...
</form>

ดังนั้นทางออกของปัญหาคือการเพิ่มเขตข้อมูล authenticity_token หรือใช้ตัวช่วยสร้างทางรถไฟแทนการรักษาความปลอดภัยเป็นต้น


1
ขอบคุณสำหรับคำตอบของคุณแม้ว่าจะไม่ได้ตอบคำถามเดิม คำถามที่ถามเกี่ยวกับการตอบสนองต่อคำขอ JSON แต่คุณกำลังให้บริการโซลูชั่นสำหรับฟอร์ม HTML ตั้งแต่เริ่มต้น เมื่อทำการร้องขอ JSON (คิดว่า API) คุณจะไม่ส่งแบบฟอร์ม HTML และคุณอาจไม่สามารถเข้าถึงโทเค็นของแท้ได้อย่างง่ายดาย
alexcoco

เว้นแต่เนื้อหาของการร้องขอเป็นจริง JSON application/jsonซึ่งในกรณีที่คุณต้องการจะตั้งค่าให้
alexcoco

ฉันเข้าใจว่าคำตอบนั้นไม่ใช่สิ่งที่คุณกำลังมองหา แต่จุดประสงค์ของการวางคำตอบที่เกี่ยวข้องคือเพื่อช่วยให้ผู้ใช้มองหา "ปัญหาของแท้" ที่คล้ายกัน
amjad

ขออภัยฉันลบออกโดยไม่ตั้งใจ - "คุณสามารถตั้งค่า Content-Type: application / x-www-form-urlencoded ด้วยวิธีแก้ไขด้านบน"
amjad

0

การทดสอบทั้งหมดของฉันทำงานได้ดี แต่ด้วยเหตุผลบางอย่างฉันได้ตั้งค่าตัวแปรสภาพแวดล้อมของฉันเป็นไม่ใช่การทดสอบ:

export RAILS_ENV=something_non_test

ฉันลืมยกเลิกการตั้งค่าตัวแปรนี้เนื่องจากฉันเริ่มได้รับการActionController::InvalidAuthenticityTokenยกเว้น

หลังจากยกเลิก$RAILS_ENVการตั้งค่าการทดสอบของฉันก็เริ่มทำงานอีกครั้ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.