ruby-on-rails - 升級到設計3.1 =>獲取重置密碼令牌無效





devise ruby-on-rails-4 factory-bot rspec2 (6)


在您的設計重置密碼模板中,確保以下內容應該更正:

= link_to'更改我的密碼',edit_password_url(@resource,:reset_password_token => @token)

感謝史蒂文哈曼的這個gist ,我得到了它的工作。 devise_mail_helpers.rb

module Features
  module MailHelpers

    def last_email
      ActionMailer::Base.deliveries[0]
    end

    # Can be used like:
    #  extract_token_from_email(:reset_password)
    def extract_token_from_email(token_name)
      mail_body = last_email.body.to_s
      mail_body[/#{token_name.to_s}_token=([^"]+)/, 1]
    end

  end
end

我將文件devise_mail_helpers.rb添加到與功能規範相同的文件夾中,並編寫了此規範。

require 'devise_mail_helpers.rb'
include Features
include MailHelpers
describe "PasswordResets" do
  it "emails user when requesting password reset" do
    user = FactoryGirl.create(:user)
    visit root_url
    find("#login_link").click
    click_link "Forgot your password?"
    fill_in "Email", :with => user.email
    click_button "Send instructions"
    current_path.should eq('/users/sign_in')
    page.should have_content("You will receive an email with instructions about how to reset your password in a few minutes.")
    last_email.to.should include(user.email)
    token = extract_token_from_email(:reset_password) # Here I call the MailHelper form above
    visit edit_password_url(reset_password_token: token)
    fill_in "user_password", :with => "foobar"
    fill_in "user_password_confirmation", :with => "foobar1"
    find('.signup_firm').find(".submit").click
    page.should have_content("Password confirmation doesn't match Password")
  end
 end

這將照顧規範,使其在瀏覽器中工作,看看Dave的答案如下。

原始問題

在我的rails 4應用程序中,我已將設備升級到3.1並運行rails s ,然後我得到了這個:

`raise_no_secret_key': Devise.secret_key was not set. 
 Please add the following to your Devise initializer: (RuntimeError)
 config.secret_key = '--secret--'

我將密鑰添加到設計初始化程序。

在此之後,當我嘗試重置密碼時出現以下錯誤

Reset password token is invalid

似乎在電子郵件中發送的令牌不正確。 其他一切都在發揮作用。 我像溫暖的刀槽黃油一樣進出。

更新

現在我想它必須是一個加密reset_password_token東西來自功能規範:

user = FactoryGirl.create(:user, 
 :reset_password_token => "something", 
 :reset_password_sent_at => 1.hour.ago)
visit edit_password_url(user, :reset_password_token => 
  user.reset_password_token)
fill_in "user_password", :with => "foobar"
click_button "Change my password"
page.should have_content("Password confirmation doesn't match Password")

發生的錯誤是:

Failure/Error: page.should have_content
("Password confirmation doesn't match Password")        
expected to find text "Password confirmation doesn't match Password" in 
"Reset password token is invalid"

關於我缺少的任何想法?




我在規格上有這個錯誤。 我試圖在User上手動設置reset_password_token ,所以我可以將令牌傳遞給edit_user_password_path 。 但是,重置令牌會被哈希處理,因此手動設置它將不起作用。 哎呀! 為了避免這個錯誤,我將reset_token設置reset_token等於user.send_reset_password_instructions返回的實際令牌。

工作規範:

require 'spec_helper'

feature 'User resets password' do
  scenario 'fills out reset form' do
    user = create(:user)
    reset_token = user.send_reset_password_instructions
    new_password = 'newpassword!'
    visit edit_user_password_path(user, reset_password_token: reset_token)

    fill_in :user_password, with: new_password
    fill_in :user_password_confirmation, with: new_password
    click_button 'Change my password'

    expect(page).to have_content(
      'Your password was changed successfully. You are now signed in.'
    )
  end
end



正如其他人所指出的那樣:原因是需要改變生成包含重置密碼鏈接的郵件的視圖。

我看到了這個錯誤,因為我還在使用devise-i18n-views gem,它會生成舊的鏈接。 刪除那個寶石並依賴現在屬於devise-i18n gem的視圖解決了我的問題。




您之前對我的類似問題發表了評論,我找到了一個可能對您有幫助的答案。

升級到Devise 3.1.0在一段時間內我沒有觸及的視野中留下了一些“殘酷”。 根據這篇博客文章 ,您需要更改您的Devise郵件程序以使用@token而不是舊的@resource.confirmation_token

app/views/<user>/mailer/reset_password_instructions.html.erb它並將其更改為:

<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

這應該可以解決您遇到的任何基於令牌的確認問題。 這也可能解決任何解鎖或確認令牌問題。




我猜你已經將Devise升級到v3.1而不是v3.01,因為config.secret_key 。 所以我認為它與新的設計功能 - 秘密密鑰有某種關聯。
我找到了兩個秘密密鑰功能的提交,可以幫助更好地理解: https://github.com/plataformatec/devise/commit/32648027e282eb4c0f4f42e9c9cc0c961765faa8https://github.com/plataformatec/devise/commit/32648027e282eb4c0f4f42e9c9cc0c961765faa8 https://github.com/plataformatec/devise/commit/d56641f514f54da04f778b2a9b816561df7910c2

您可能會在http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/上找到對您有用的內容。
您也可以在https://github.com/plataformatec/devise/compare/v3.0...v3.1.0上grep reset_password_token

編輯
請閱讀http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

  • Devise郵件程序現在在每個方法上接收一個額外的標記參數。 如果您已自定義Devise郵件程序,則必須更新它。 所有郵件程序視圖也需要更新以使用@token ,如此處所示,而不是直接從資源獲取令牌;



token_authenticatable容易受到時間攻擊的影響, 本博文中對此進行了詳細解釋。 這些攻擊是從Devise 3.1中刪除token_authenticatable的原因。 有關詳細信息,請參閱plataformatec博客文章

要擁有最安全的令牌認證機制,令牌:

  1. 必須通過HTTPS發送。

  2. 密碼強度必須是隨機的。

  3. 必須安全地進行比較。

  4. 不得直接存儲在數據庫中。 只有令牌的哈希值才能存儲在那裡。 (記住,令牌=密碼。我們不在db中以明文形式存儲密碼,對吧?)

  5. 應該按照一些邏輯到期。

如果你放棄其中一些支持可用性的觀點,你最終會得到一種不那麼安全的機制。 就這麼簡單。 如果您滿足前三個要求並限制對數據庫的訪問,那麼您應該足夠安全。

擴展並解釋我的答案:

  1. 使用HTTPS 。 這絕對是最重要的一點,因為它涉及嗅探器。

    如果你不使用HTTPS,那麼很多都可能出錯。 例如:

    • 為了安全地傳輸用戶的憑據(用戶名/電子郵件/密碼),您必須使用摘要式身份驗證,但這些日子並沒有削減它,因為鹽漬哈希可能是強制性的

    • 在Rails 3中,cookie僅由Base64編碼覆蓋,因此可以很容易地顯示它們。 有關詳細信息,請參閱解碼Rails會話Cookie

      但是,從Rails 4開始,cookie存儲區被加密,因此數據經過數字驗證,對攻擊者來說無法讀取。 只要您的secret_key_base沒有洩露,Cookie就應該是安全的。

  2. 使用以下內容生成令牌:

    為了解釋為什麼這是必要的,我建議閱讀sysrandom的自述文件和博客文章如何在各種編程語言中生成安全隨機數

  3. 使用用戶的ID,電子郵件或其他屬性查找用戶記錄。 然後,將該用戶的令牌與請求的令牌與Devise.secure_compare(user.auth_token, params[:auth_token] 。如果您使用的是Rails 4.2.1+,則還可以使用ActiveSupport::SecurityUtils.secure_compare

    使用像User.find_by(auth_token: params[:auth_token])這樣的Rails查找程序找不到用戶記錄。 這很容易受到時間攻擊!

  4. 如果您要為每個用戶同時擁有多個應用程序/會話,那麼您有兩個選擇:

    • 將未加密的令牌存儲在數據庫中,以便可以在設備之間共享。 這是一種不好的做法,但我想你可以用UX的名義來做(如果你信任你的員工有DB訪問權限)。

    • 為每個用戶存儲盡可能多的加密令牌,以允許當前會話。 因此,如果要在2個不同的設備上允許2個會話,請在數據庫中保留2個不同的令牌哈希值。 這個選項實施起來不那麼簡單,但它肯定更安全。 它還具有以下優勢:允許您通過撤銷其令牌為用戶提供在特定設備中結束當前活動會話的選項(就像GitHub和Facebook一樣)。

  5. 應該有某種機制導致令牌過期。 在實施此機制時,請考慮用戶體驗與安全性之間的權衡。

    如果令牌未使用六個月,則Google會過期

    Facebook如果未使用兩個月就會過期

    使用Facebook SDK的原生移動應用程序將獲得長期訪問令牌,大約可以使用60天。 當使用您的應用程序的人向Facebook的服務器發出請求時,這些令牌將每天刷新一次。 如果沒有請求,則令牌將在大約60天后過期,並且該人將不得不再次通過登錄流程以獲得新令牌。

  6. 升級到Rails 4以使用其加密的cookie存儲。 如果你不能,那麼自己加密cookie商店,就像here建議的那樣。 將身份驗證令牌存儲在加密的Cookie存儲中絕對沒有問題。

您還應該有一個應急計劃,例如,rake任務可以重置令牌子集或數據庫中的每個令牌。

為了幫助您入門,您可以查看關於如何使用Devise實現令牌認證的這一要點 (由Devise的作者之一)。 最後, 關於保護API的Railscast應該會有所幫助。







ruby-on-rails devise ruby-on-rails-4 factory-bot rspec2