Rails сохранение простой старой строки в SQlite как BLOB?Я сейчас с ума сойду! - PullRequest
5 голосов
/ 04 июля 2011

Я понятия не имею, почему это происходит, но Rails сохраняет строку в SQLite как BLOB.Перед созданием нового пользователя в моем приложении я беру его простой строковый пароль и MD5 перед сохранением в базу данных:

class User < ActiveRecord::Base
  before_create :encrypt_password

  def encrypt_password
    self.password = Digest::MD5.hexdigest(self.password)
  end
end

Но поле пароля каждый раз переходит в SQLite в виде чертова BLOB!Единственный способ, который я мог бы сказать, - при экспорте таблицы в SQL я вижу истинную природу поля:

INSERT INTO "users" VALUES (24, 'john.doe@example.com', X'3639366432396530393430613439353737343866653366633965666432326133');

Что за черт ??Поэтому теперь, когда я пытаюсь аутентифицировать пользователя, просматривая его электронную почту и хешированный пароль MD5, каждый раз происходит сбой.Реальные строки не соответствуют BLOB-объектам:

User.find_by_email_and_password('john.doe@example.com', Digest::MD5.hexdigest('password') => nil

Я никогда в своей жизни не использовал BLOB-объект, не говоря уже о поле пароля для пользовательской таблицы.Мои миграции четко определяют :string как тип данных.Выполнение User.columns ясно показывает:

#<ActiveRecord::ConnectionAdapters::SQLiteColumn:0x00000105256ce0 @name="password", @sql_type="varchar(255)"

Я работал над этим приложением большую часть месяца и никогда не видел эту проблему до прошлой ночи, когда я писал некоторые тесты для пользователя.модель.Каждый раз при попытке аутентификации пользователя произойдет сбой, поэтому я начал вручную собирать пользователей в консоли и пришел к выводу, что пароль никогда не будет совпадать, поэтому поиск всех пользователей завершится неудачей.

Информация отладки Rails для созданияпользователь выглядит так:

INSERT INTO "users" ("created_at", "email", "first_name", "last_login_at", "last_name", "login_count", "password", "role_id", "twitter", "updated_at", "uuid") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["created_at", Mon, 04 Jul 2011 18:50:58 UTC +00:00], ["email", "braulio_towne@runolfsson.name"], ["first_name", "Ebba"], ["last_login_at", nil], ["last_name", "Bayer"], ["login_count", nil], ["password", "5f4dcc3b5aa765d61d8327deb882cf99"], ["role_id", 2], ["twitter", nil], ["updated_at", Mon, 04 Jul 2011 18:50:58 UTC +00:00], ["uuid", "7ab57110-889c-012e-e207-482a140835c4"]]

Что, когда я конвертирую в обычный SQL, работает нормально, так что где-то еще что-то происходит.Что происходит?!?!

  • sqlite3 3.6.12
  • рельсы 3.1.0.rc4
  • sqlite3-ruby 1.3.3

ОБНОВЛЕНИЕ

Становится незнакомым и незнакомым ... если я жестко закодирую некоторую случайную строку в моем методе encrypt_password, то он корректно попадает в базу данных:

def encrypt_password
  self.password = 'foo'
end

Я могудаже жестко закодировать его в фактический хэш MD5 строки 'password', и он работает:

def encrypt_password
  self.password = '5f4dcc3b5aa765d61d8327deb882cf99'
end

Но если я скажу это Digest::MD5.hexdigest('password'), тогда он будет введен как BLOB.

Теперь, если я добавлю что-нибудь в строку, созданную дайджестом, то это сработает!

def encrypt_password
  self.password = Digest::MD5.hexdigest(self.password) + ' '
end

Что это за черт ??Итак, сейчас моя тренировка состоит в том, чтобы добавить новую строку, а затем сжать ее:

def encrypt_password
  self.password = (Digest::MD5.hexdigest(self.password) + "\n").chomp
end

Я чувствую, что должен где-то открыть билет в Rails, но это настолько удивительно, что я не хочурассмеяться над сообществом навсегда, даже предположив, что что-то подобное может произойти!

Ответы [ 2 ]

6 голосов
/ 06 июля 2011

Оказывается, это была проблема с кодировкой. Смотри билет здесь: https://github.com/rails/rails/issues/1965

hexdigest возвращает строку ASCII, но когда вы возвращаетесь к запросу по тому же полю, запрос выполняется как строка UTF-8. Я предполагаю, что, как только я вручную что-то добавил в строку, она была закулисно преобразована в UTF-8 и затем должным образом сохранена в БД как UTF-8. Вот исправление:

def encrypt_password
  self.password = Digest::MD5.hexdigest(self.password).encode('UTF-8')
end
0 голосов
/ 05 июля 2011

Прямое хеширование MD5 не очень хорошо для безопасности. Кто-то взламывает базу данных электронной почты / паролей в другом месте, используя этот метод, и они могут легко взломать ваш сайт.

Рассмотрите возможность использования Bcrypt. Следующее взято с http://bcrypt -ruby.rubyforge.org :

require 'bcrypt'

class User < ActiveRecord::Base
  # users.password_hash in the database is a :string
  include BCrypt

  def password
    @password ||= Password.new(password_hash)
  end

  def password=(new_password)
    @password = Password.create(new_password)
    self.password_hash = @password
  end

end

Добавить миграцию для переименования «пароля» в «password_hash».

Это также должно повлиять на решение проблемы с сериализацией, возникающей у вас в результате использования метода hexdigest.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...