- 投稿日:2019-02-26T22:50:36+09:00
Railsでdeviseを使おうとした時のエラー
今回のエラー
NoMethodError (undefined method `devise' for User (call 'User.connection' to establish a connection):Class):というエラーが出る
エラーが出た時の流れ
1.gemfileにgem 'devise'を入力
↓
2.ターミナルでbundle install
↓
3.rails sでサーバ立ち上げ
↓
4.rails g devise:install
↓
5.rails g model user
↓
6.rake db:migrateの流れのあと、
エラー解決策
サーバーを再起動して解決
思わぬところにエラーが....
- 投稿日:2019-02-26T22:00:26+09:00
Ruby irb、テキストエディタ使用とエラー解決方法
動作環境はMacとなります。
主に自分の勉強用メモとして残しています。Rubyプログラム irb使用
文字列はシングルクオートかダブルクオートで囲む
irb(main):001:0> "Hello, World" => "Hello, World"#Rubyは最後の式を自動的に出力するので、プログラムとは言えない。putsは何かを出力する命令で、これをつけることでプログラムと言える。
irb(main):004:0> puts 'Hello World!'#これがプログラム Hello World! => nil#putsは必ずnilを返す数値の計算
irb(main):005:0> 1 + 1 => 2 irb(main):006:0> 10 - 1 => 9irbで記述したプログラムをクリアしたい時
clear か control+lキー
irbを終了したい場合
exit か contol+dキー
テキストエディタ使用
この環境ではAtom使用しています。
$はターミナルでの操作を表します。ファイル作成
$mkdir ruby_projects #mkdirはmake directoryの略でファイル作成の意味$ls #今いるディレクトリの中身を確認 $cd ruby_projects/ #今いるディレクトリから移動 $touch hello.rb #ファイル作成 $atom . #Atomを開く時のコマンドrubyプログラムを作成する場合、拡張子は.rbとする。
テキストエディタ
hello.rbputs 'Hello, World!'#行末に;をつけてもエラーにはならないが、rubyは改行で認識されるため通常書かない puts 10 + 3ターミナル
$ ruby hello.rb #ruby + ファイル名で出力 Hello, World! 13Linuxコマンド
現在のディレクトリをカレントディレクトリという。
ディレクトリとファイルはざっくり同じ。$ pwd #現在いるファイルの階層を表示 $ cd .. #現在いるフォルダの1つ上の階層に移動 $ ls #現在いるフォルダの中身を表示エラーを自力で取り除く方法
hello.rbputs 'Hello, World!' put 10 + 3 #putsをputと間違えたターミナル
$ ruby hello.rb Hello, World! #問題なく出力される。 hello.rb:2:in `<main>': undefined method `put' for main:Object (NoMethodError) #hello.rbファイルの二行目のputというメソッドがないよというエラー Did you mean? puts putc #もしかしてこういう意味?とエラーが教えてくれている。メソッドとは処理のまとまりのこと。
エラーメッセージをグーグル検索すると、解決の意図が見つかることが多い。
特にrubyは日本で広く普及されているので、情報が見つかりやすい。以上を踏まえて修正
hello.rbputs 'Hello, World!' puts 10 + 3 #putをputsへ修正ターミナル
$ ruby hello.rb Hello, World! 13正常にプログラムが実行された!
- 投稿日:2019-02-26T18:49:40+09:00
Dockerでコンテナのbashに入ってからコマンド打てなかった話
なんの話するの
MySQLでエラー頻発するようになって、
Dockerに移行しようと思い付き、
いまいじっているが。。コンテナに対してbashを起動したあと、
何したらいいのかわからなかったので
備忘録としてまとめておく。コンテナに対するbashとは?
ターミナルのこと。
そのコンテナ上で(=作業したいapp(コンテナ)に対して)ターミナルを起動させる。イメージをビルドしたあと、
docker-composer run potepanec bashを実行、これによりサービス名「potepanec」のコンテナに対してbash(ターミナル)が起動される。
その次僕は
root@a2953f92ffc3:/tmp`# bundle exec rails sと打ったが
Usage: rails new APP_PATH [options] Options: [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated applications) -r, [--ruby=PATH] # Path to the Ruby binary of your choice # Default: /usr/local/bin/ruby -m, [--template=TEMPLATE] # Path to some application template (can be a filesystem path or URL) -d, [--database=DATABASE] # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc) # Default: sqlite3 [--skip-yarn], [--no-skip-yarn] # Don't use Yarn for managing JavaScript dependencies [--skip-gemfile], [--no-skip-gemfile] # Don't create a Gemfile -G, [--skip-git], [--no-skip-git] # Skip .gitignore file [--skip-keeps], [--no-skip-keeps] # Skip source control .keep files -M, [--skip-action-mailer], [--no-skip-action-mailer] # Skip Action Mailer files -O, [--skip-active-record], [--no-skip-active-record] # Skip Active Record files [--skip-active-storage], [--no-skip-active-storage] # Skip Active Storage files -P, [--skip-puma], [--no-skip-puma] # Skip Puma related files -C, [--skip-action-cable], [--no-skip-action-cable] # Skip Action Cable files -S, [--skip-sprockets], [--no-skip-sprockets] # Skip Sprockets files [--skip-spring], [--no-skip-spring] # Don't install Spring application preloader [--skip-listen], [--no-skip-listen] # Don't generate configuration that depends on the listen gem [--skip-coffee], [--no-skip-coffee] # Don't use CoffeeScript -J, [--skip-javascript], [--no-skip-javascript] # Skip JavaScript files [--skip-turbolinks], [--no-skip-turbolinks] # Skip turbolinks gem -T, [--skip-test], [--no-skip-test] # Skip test files [--skip-system-test], [--no-skip-system-test] # Skip system test files [--skip-bootsnap], [--no-skip-bootsnap] # Skip bootsnap gem [--dev], [--no-dev] # Setup the application with Gemfile pointing to your Rails checkout [--edge], [--no-edge] # Setup the application with Gemfile pointing to Rails repository [--rc=RC] # Path to file containing extra configuration options for rails command [--no-rc], [--no-no-rc] # Skip loading of extra configuration options from .railsrc file [--api], [--no-api] # Preconfigure smaller stack for API only apps -B, [--skip-bundle], [--no-skip-bundle] # Don't run bundle install [--webpack=WEBPACK] # Preconfigure for app-like JavaScript with Webpack (options: react/vue/angular/elm/stimulus) Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Rails options: -h, [--help], [--no-help] # Show this help message and quit -v, [--version], [--no-version] # Show Rails version number and quit Description: The 'rails new' command creates a new Rails application with a default directory structure and configuration at the path you specify. You can specify extra command-line arguments to be used every time 'rails new' runs in the .railsrc configuration file in your home directory. Note that the arguments specified in the .railsrc file don't affect the defaults values shown above in this help message. Example: rails new ~/Code/Ruby/weblog This generates a skeletal Rails installation in ~/Code/Ruby/weblog.と出てきて、進まなくなった。
ふーん、けど見た感じ
rails new
はいけなくもないのか。
→てことは(これから編集したい)アプリが認識されていない?
→そもそもパスが違う?たったのこれだけだった
root@a2953f92ffc3:/tmp$ bundle exec rails stmpってなんだよtmpって
root@a2953f92ffc3:/tmp$ cd ..の結果、
root@a2953f92ffc3:/$あ〜作業ディレクトリに入ってなかったのね。
bash起動したらtmpっていう作業フォルダじゃないとこに入っちゃったのか。てなわけで
root@a2953f92ffc3:/$ ls bin boot bundle dev etc home lib lib64 media mnt opt potepanec proc rails root run sbin srv sys tmp usr varpotepanecに入ろう
root@a2953f92ffc3:/$ cd potepanec root@a2953f92ffc3:/potepanec$ ls Dockerfile.dev Gemfile Gemfile.bak Gemfile.lock Gemfile.lock.bak README.md Rakefile WITHOUTDOCKER.md app bin config config.ru db docker-compose.yml docs lib log node_modules package.json public tmp vendorおーいつもの顔ぶれ!
てことで、ただ単に作業ディレクトリに移動してなかったってだけでした。誰かの役に立てたら、と思って記事書いたけど、こんなん間違うの俺だけかも?
おわり
- 投稿日:2019-02-26T17:52:54+09:00
terraformでrailsが動くAWSの環境を作る
ほとんど自分用のメモですが、ローカルだけに保存しておくのも微妙なので、Qiitaにあげておきます。
とあるサービスをリリースした際に使用したTerraformを軽く書き直して、githubにあげました
https://github.com/okbm/terraform-railsec2 + rds + https + route53で動くごく普通の構成です。
rubyのインストールはやってますが、railsのインストールは別途必要です。対応できていないところ
- 最新のTerraformのバージョンではない
- 0.11.08で動かしている(現時点での最新は0.11.11)
- stg対応
- stgが環境的に存在していない。
- 0.11.10でworkspaceができたのでそれでやったほうがいいと思います。
- tfstateをs3で管理するところ
ハマったところ
- ec2立ち上がった後にRubyのインストール等したいので、
remote-exec
で実行しようとしたけど、インスタンスが起動するまでIPアドレス等がわからないので結局動かない
null_resource
をつかってec2のwebが立ち上がった後に起動にした- 設定を書いて、
apply
してを繰り返しているとめんどくさくなったので、 dtan4/terraforming: Export existing AWS resources to Terraform style (tf, tfstate)を使って、コンソールで入れたやつを抜いたりした- フォルダ構成が未だによくわからない
- 1ファイル1設定にしてる構成とか見かけたけど、やりすぎな気がするのでまぁ自分がわかりやすいのでいいやと思ってフィーリングでフォルダ掘った
- 投稿日:2019-02-26T15:57:53+09:00
Railsで「+ 1」と「+1」が違うとき
ただのタイポによるエラーだったのだけど、「なんでArgumentError?」と考えてみたら面白かったのでメモ。
# Hogeクラスをつくって class Hoge attr_accessor :count end hoge = Hoge.new # hoge.countに値を入れる hoge.count = 1 p hoge.count # => 1 # hoge.countを1増やす hoge.count = hoge.count + 1 p hoge.count # => 2 # hoge.countをもう1増やそうと思うと hoge.count = hoge.count +1 # => 3になる、と思いきやエラーになる # ArgumentError: # wrong number of arguments (given 1, expected 0)なぜかというと、1のコードは2のコードと同じ。
# 1 class Hoge attr_accessor :count end # 2 class Hoge def count @count end def count=(count) @count = count end endRubyの場合、メソッドの引数は
()
に入れて渡すのだけれど、省略可能になっている。hoge.count + 1 # => これはgetterのcountメソッドにアクセスして、その返り値に +1している # 評価順はこう # (hoge.count) + 1hoge.count +1 # => この場合+1がgetterの引数になっている # 評価順はこう # hoge.count(+1)
+1
の(スペースが間に入らない)場合、呼び出されるのはgetterのcountで、
getterは引数を取るよう定義されていないのでArgumentErrorが発生する。
だから、こうすれば通るけど、jsでよくかかれるような+=
とは違う結果になる。hoge.count = 1 hoge.count = +1 # => 1 # +1されて2が返るのではなく、何度やっても1が返る hoge.count = +1 # => 1
- 投稿日:2019-02-26T15:57:53+09:00
Rubyで「+ 1」と「+1」が違うとき
ただのタイポによるエラーだったのだけど、「なんでArgumentError?」と考えてみたら面白かったのでメモ。
# Hogeクラスをつくって class Hoge attr_accessor :count end hoge = Hoge.new # hoge.countに値を入れる hoge.count = 1 p hoge.count # => 1 # hoge.countを1増やす hoge.count = hoge.count + 1 p hoge.count # => 2 # hoge.countをもう1増やそうと思うと hoge.count = hoge.count +1 # => 3になる、と思いきやエラーになる # ArgumentError: # wrong number of arguments (given 1, expected 0)なぜかというと、1のコードは2のコードと同じ。
# 1 class Hoge attr_accessor :count end # 2 class Hoge def count @count end def count=(count) @count = count end endRubyの場合、メソッドの引数は
()
に入れて渡すのだけれど、省略可能になっている。hoge.count + 1 # => これはgetterのcountメソッドにアクセスして、その返り値に +1している # 評価順はこう # (hoge.count) + 1hoge.count +1 # => この場合+1がgetterの引数になっている # 評価順はこう # hoge.count(+1)
+1
の(スペースが間に入らない)場合、呼び出されるのはgetterのcountで、
getterは引数を取るよう定義されていないのでArgumentErrorが発生する。
だから、こうすれば通るけど、jsでよくかかれるような+=
とは違う結果になる。hoge.count = 1 hoge.count = +1 # => 1 # +1されて2が返るのではなく、何度やっても1が返る hoge.count = +1 # => 1
- 投稿日:2019-02-26T15:31:02+09:00
Mac(Mojave)でRails5系でmysql2をinstallしようとするとDon't know how to set rpath on your system... エラー
背景
ローカルMac(Mojave)でRails5.2でmysql2をbundle installしようとしたら以下のようなエラーでた
Building native extensions. This could take a while... ERROR: Error installing mysql2: ERROR: Failed to build gem native extension. . . checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/bin/mysql_config ----- . . ----- Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/Cellar/mysql/5.7.20/lib ----- . .やったこと
macOS_SDK_headers_for_macOS_10.14.pkg
を起動する。以下のコマンドから飛べる。open /Library/Developer/CommandLineTools/Packages/だめだったこと
xcode-select --install
だけでは解決しませんでした- あと bundle install 時、mysql2でエラー のまとめていただいているのは一通りためしてみました。上記のやりかたでだめだったら試してみてください。
- 投稿日:2019-02-26T15:31:02+09:00
Mac(Mojave)でRails4.6系/ruby2.6系でmysql2をinstallしようとするとDon't know how to set rpath on your system... エラー
背景
ローカルMac(Mojave)でRails4.6系/ruby2.6系でmysql2をbundle installしようとしたら以下のようなエラーでた
Building native extensions. This could take a while... ERROR: Error installing mysql2: ERROR: Failed to build gem native extension. . . checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/bin/mysql_config ----- . . ----- Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/Cellar/mysql/5.7.20/lib ----- . .やったこと
macOS_SDK_headers_for_macOS_10.14.pkg
を起動する。以下のコマンドから飛べる。open /Library/Developer/CommandLineTools/Packages/だめだったこと
xcode-select --install
だけでは解決しませんでした- あと bundle install 時、mysql2でエラー のまとめていただいているのは一通りためしてみました。上記のやりかたでだめだったら試してみてください。
- 投稿日:2019-02-26T13:43:25+09:00
Sidekiqで処理待ち、処理中のjobを取得する
ActiveJob
でqueue adaptorにSidekiq
を使ってて、ジョブの状況を確認したいので調査しました![]()
環境
sidekiq (5.1.1)
コード
# 処理中のjob workers = Sidekiq::Workers.new workers.each do |_process_id, _thread_id, work| p work end # 処理待ちのjob queues = Sidekiq::Queue.all queues.each do |queue| queue.each do |job| p job.klass, job.args, job.jid end end以上です
![]()
参考
- 投稿日:2019-02-26T11:44:19+09:00
hamlでclass名を動的に設定する
hamlのdivは%divを省略することができるが、
div%div.alert .alertclass名を動的に設定するなら、
%div記法を使わないとできない。flash- flash.each do |message_type, message| %div{class: "alert alert-#{message_type}"} =message
- 投稿日:2019-02-26T10:00:36+09:00
each内でのrenderパーシャルをcollectionに変更し高速化
問題
ビュー内で部分テンプレートをeachで呼び出す際に困ったこと。
例)ルート(welcome)画面でピックアップした商品一覧を表示(商品一覧は他の画面でも使うためパーシャル化)
welcome_controller.rb@pickups = Product.all.where.not(pickup_at: nil).joins_i18n(locale_id: @current_lang.id).includes(countries: :country_i18ns).shufflewelcome.html.erb#問題点のみ抜粋 <% @pickups.each do |p| %> <%= render partial: '/shared/products/index_item', locals: { p: p } %> <% end %> -->/shared/products/_index_item.html.erb<div class="col-xs-6 col-md-3"> <section class="product_list"> <%= link_to product_maker_path(id: p.maker_id, product_id: p.id) do %> <div class="photo_box"> <div class="photo_inner photo_contain" style="background-image:url(<%= asset_path p.main_image.thumb %>);" > <% p.campaigns.each do |camp| %> <div class="cam_lavel"><%= camp.i18n.label %></div> <% end %> </div> </div> <div class="pdt_list_ex"> #以下省略eachで回す度にパーシャルファイルを呼んでしまう。
読み込み速度が遅い。。。。。解決策
each内ではなく、collectionを使ってパーシャルをrenderする
welcome.html.erb<%= render partial: '/shared/products/index_item', collection: @pickups, as: :p %>パーシャルを呼び出すのは1回。
- 投稿日:2019-02-26T09:00:15+09:00
Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile. (Gem::LoadError)
bin/rails g ...
する際にsqlite3
のversion依存関係で怒られたので解決法を調べた。解決方法
Gemfile.- gem 'sqlite3' + gem 'sqlite3', '~> 1.3.6'$ bundle install原因
リンク先に詳細が記載されている。
- Railsを始めてsqlite3まわりのエラーで躓いている人たちへ
- 投稿日:2019-02-26T08:41:47+09:00
Error: qt@5.5: unknown version :mountain_lion
- 投稿日:2019-02-26T03:38:51+09:00
Rubyでもbcryptはバイナリセーフではない
RubyのBCryptはバイナリセーフなのか
徳丸先生が注意喚起としてあげられていたこちらの記事に関して
“bcryptの72文字制限をSHA-512ハッシュで回避する方式の注意点 | 徳丸浩の日記” https://t.co/AA1yFVd0TH
— 徳丸 浩 (@ockeghem) 2019年2月24日
記事ではPHPの例が上がっていましたが、Rubyではどのような影響があるのかが気になります。BCryptは非常にメジャーなアルゴリズムで、例えば
Devise
やSorcery
などの定番の認証gemを使う場合、デフォルトでBCryptを利用する設定になっています。Railsアプリを開発されている方なら、ほとんどの方が使っているのではないでしょうか。詳しくは徳丸ブログを見ていただくとして、以下ではbcrypt-rubyについて、同じ現象が起こるのかどうか簡単に調査しています。
TL;DR
BCryptを使って バイナリをハッシュ化してはならない
- バイナリコード0x00にヒットすると以降のハッシュ化を止める
- それにより実際より短い部分文字列だけを照合してしまう可能性がある
- とくに冒頭に0x00を含むパスワードを指定すると、簡単に破られてしまう
BCryptに通す前に自前でハッシュ関数を適用したり、BCryptでバイナリをハッシュ化するというような特殊用途で使用している場合は要注意
- セキュリティ面の問題がある
- 未来のバージョンで、今まで通っていたパスワードが通らなくなる可能性がある(後述)
「ユーザーからの入力パスワードをテキストのままdeviseに渡す」というように、一般的な使い方をしている分には問題にならないと思われます。
実験してみる
徳丸ブログに指摘されている内容はいくつかのステップがあります。
それぞれRubyのBCrypt実装においても同様の現象が起こるかどうかを確認していきます。72文字を超えるパスワード文字列は切り捨てられるか
実験のために、BCryptでハッシュ化された長いパスワードを用意します。
(ストレッチ回数などはデフォルト設定です)>> require 'bcrypt' # 72文字を超える長いパスワードを用意する >> password1 = 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong_password' >> password1.length => 81 # BCryptオブジェクトを作る >> bcrypted_password1 = BCrypt::Password.create(password1) => "$2a$10$gSsEckxXdY26QjgVuibuZ.J.nAxVpAyMVW6GWjKI9ouOVBEbPiitm"ここで作成したBCryptオブジェクトと候補文字列を
==
で比較すると、「ハッシュ化した時に同じハッシュを得られるかどうか(≒ 元のパスワードが一致するかどうか)」を判定してくれます。1パスワード認証を通す・通さないの判定に使われている仕組みですね。
# 一致する >> crypted_password1 == 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong_password' => true # もちろん適当な文字列を入れても一致しない >> crypted_password1 == 'a_totally_different_thing' => falseところが・・
# パスワード後半を変更する >> crypted_password1 == 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong_cucumber' => true >> crypted_password1 == 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooongSpeach' => true後半(73文字以降)がハッシュ化の際に捨てられていることがわかります。
もちろん72文字以前を変更した場合は不一致となります。
>> 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong'.length => 72 >> crypted_password1 == 'a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooonG_password' => false前提となるパスワード文字列の制限については、ドキュメントには明記されていないようですが、RubyのBCryptでも同様に起こることがわかります。
実装はcrypt(3)ライブラリに準拠していると思われるので当然といえば当然ですね。
長い文字列をハッシュ化するときの落とし穴
ここで何らかの事情で「どうしても72文字以上ある長い文字列のハッシュをBCryptで取りてえ」となったとします。
上記の切り捨てを回避するため、「別のアルゴリズムでいったん短いハッシュを作ってから、BCryptに食わせる」という手段が思い浮かびます。ハッシュが長いテキストだと結局また切り落としが発生するのですが、バイナリハッシュを使うと72文字以下におさめることができそうです 2
比較演算子
==
が使えるように、雑に実装してみたのが下記です。require 'digest' class VeryUnsafeDigest def initialize(password) @password = password @digest = create_digest end def create_digest temporary_digest = Digest::SHA512.digest(@password) BCrypt::Password.create(temporary_digest) end def ==(other) @digest == Digest::SHA512.digest(other) end end>> digest1 = VeryUnsafeDigest.new(password1) >> digest1 == "a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong_password" => true >> digest1 == "a_rediculously_loooooooooooooooooooooooooooooooooooooooooooooooooooooong_beard" => false今度は長いパスワードをうまく区別してくれました。
一見うまくいったように見えます。が・・
>> digest2 = VeryUnsafeDigest.new('good_looking_password_380') >> digest2 == 'RandomString105' => true >> digest2 == 'good_looking_password_420' => trueなんと、3つの完全に異なるパスワードが すべて衝突してしまいました。
これらの文字列は、バイナリハッシュの段階で冒頭に0x00が含まれてしまっています。
>> Digest::SHA512.digest 'good_looking_password_380' => "\x00\xB6\xE5\xE65\\\x91j\xD3\t\xB4\x98h\x81\xBD\x0E\xB1\\\xC3$\xCB\xD2\x80\x85\xB6\xEC\x18B\xCC\xE4\r\xC3\x93\xA1j*4P\x97\xF0y\x17\xD7P\x11h\x96iq\xFE\x7F\xDB\x10(\n\xDC\xB8\xAF8ESe>\xDD"つまりBCryptは、この文字列の冒頭が終端だと判断して処理を終了してしまい、残りのハッシュ化をしません(空文字列を渡された場合と実質同じ処理になる)。
やはりRuby実装でも、BCryptは0x00を終端文字列と解釈し、残りの文字列を切り捨ててしまうことが確認できます。
今後の動き
この問題についてはbcrypt-rubyリポジトリでもイシューがいくつか出ているようで、「文字列中に0x00が入ってきた場合には例外を吐かせる」というパッチを我らが
たこやきアーロン巨匠が提案してくれています。これによって、何かの間違いでうっかりBCryptにバイナリを食わせる仕様にしてしまったとしても、上で書いたような「後ろが切り捨てられるパスワード」についてはDBに投入される前に阻止できそうです。
みんなでいいねを押して応援しましょう!もし上記のようなオレオレ実装をしていた場合、このパッチが入るバージョン以降は一部のパスワードが通らなくなると思われるので、万が一そんなことがあった場合は注意してください。
セキュリティの分野において、ライブラリをハックしたりアルゴリズムを再発明するのは、かえって脆弱性を産むことになるので避けましょうということですね ?
じゃあどうすりゃいいの
RubyGemsで確認すると、Argon2のリポジトリがあるようです。徳丸先生のブログによると、PHPのArgon2は72文字制限はなくバイナリセーフであるようだ、となっています(Ruby実装については不明)
私には使える・使えないの判断ができるほど実装が理解できていない上に、まだまだ利用実績が少ないため(編集時点で64,607ダウンロード。対するBCryptは51,359,582ダウンロード)紹介するのは控えます。
もっと乱暴に「SHAだけを通す」という方法が考えられますが、今度は短いパスワードがレインボーテーブルで簡単に突破される、という状態になり極めて脆弱になります。(ためしに
SHA rainbow table
でググって出てきたサイトに、SHA512でハッシュ化した短いパスワードを投げてみたところ、ものの数秒で解読されました)。パスワード管理については流出リスクなどを考えて使わない方がよいと思われます。というわけで、素直にBCryptを使い、長いパスワードを末尾部分についてはあきらめて「72文字までの一致を見る」(入力パスワードが72文字を超えた場合はユーザーにエラーを返す)ということで割り切るのが、現時点ではもっとも素直な解決策のように思いました。
追記
2/26 ご指摘を受けてタイポ修正、一部わかりにくい表現を追記・編集しました