Обнаружение Rails 4 Сжатие файлов cookie сеанса

Фон

Я опытный веб-разработчик (в основном с Python и CherryPy), который ранее реализовал безопасное управление сеансом, и теперь изучает Rails. Я изучаю поведение сеансов Rails, как показано в объекте session, который доступен в контекстах экземпляра ActionController.

Вопрос/проблема

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

Итак, я пошел и изменил содержимое атрибута cookie сеанса с помощью надстройки браузера, и когда я перезагружу страницу с новым значением cookie, Rails просто счастливо дает мне разные новые значения для session_id и _csrf_token.

Что произошло с целостностью файлов cookie сессии?

Не должны ли рельсы обнаруживать (через подпись HMAC), что файл cookie был изменен, а затем расскажите мне об этом как-то?

Я боюсь, что мне не хватает чего-то неприлично очевидного, но мне не повезло найти ответ в Интернете, и исходный код тоже не дает его легко (я новичок в Рубин). Спасибо заранее.

Эксперимент

Я создал новое приложение и создал контроллер с действием index:

$ rails new my_app
$ cd my_app; rails g controller home index

Затем я добавил эти две строки в файл app/views/layouts/application.html.erb:

<%= session.keys %><br/>
<%= session.values %>

Я запустил сервер dev и перешел на мой браузер на "localhost: 3000/home/index". Как и ожидалось, страница имеет следующие строки внизу:

["session_id", "_csrf_token"]
["8c1558cabe6c86cfb37d6191f2e03bf8", "S8i8/++8t6v8W8RMeyvnNu3Pjvj+KkMo2UEcm1oVVZg="]

Перезагрузка страницы дает мне одинаковые значения, хотя приложение устанавливает новое значение атрибута _my_app_session cookie каждый раз. Мне это кажется странным, но я получаю одни и те же значения хэша сессии, поэтому я думаю, что это круто.

Затем я использовал надстройку редактирования файлов cookie для Chrome, чтобы изменить значение атрибута _my_app_session cookie (заменив первый символ значения атрибута). Перезагрузка страницы показывает совершенно разные значения без каких-либо действий. WAT?

Ответ 1

Я не могу претендовать на действительно полное понимание кода здесь. Но я могу сказать вам многое:

Я точно выполнил ваши шаги (используя Ruby 2.0.0-p247 и Rails 4.0), за одним исключением - я также добавил gem файл byebug в свой Gemfile и вставил точку останова отладки в действие HomeController#index.

Из консоли beebug в этой точке останова я мог видеть неотредактированный файл cookie через:

(byebug) cookies["_my_app_session"]
"cmtWeEc3VG5hZ1BzUzRadW5ETTRSaytIQldiaTMyM0NtTU14c2RrcVVueWRQbncxTnJzVDk3OWU3N21PWWNzb1IrZDUxckdMNmZ0cGl3Mk0wUGUxU1ZWN3BmekFVQTFxNk55OTRwZStJSmtJZVkzVmlVaUI2c2c5cDRDWVVMZ0lJcENmWStESjhzRU81MHFhRTN4VlNWRlJKYTU3aFVLUDR5Y1lSVkplS0J1Wko3R2IxdkVYS3IxTHA2eC9kOW56LS1IbXlmelRlSWxiaG02Q3N2L0tUWHN3PT0=--b37c705a525ab2fb14feb5f2edf86d3ae1ab03c5"

И я мог видеть фактические зашифрованные значения с помощью

(byebug) cookies.encrypted["_my_app_session"]
{"session_id"=>"13a95fb545a1e3a2d4e9b4c22debc260", "_csrf_token"=>"FXb8pZgmoK0ui0qCW8W75t3sN2KLRpkiFBmLbHSfnhc="}

Теперь я отредактирую файл cookie, изменив первую букву на "A" и обновив страницу:

(byebug) cookies["_my_app_session"]
"AmtWeEc3VG5hZ1BzUzRadW5ETTRSaytIQldiaTMyM0NtTU14c2RrcVVueWRQbncxTnJzVDk3OWU3N21PWWNzb1IrZDUxckdMNmZ0cGl3Mk0wUGUxU1ZWN3BmekFVQTFxNk55OTRwZStJSmtJZVkzVmlVaUI2c2c5cDRDWVVMZ0lJcENmWStESjhzRU81MHFhRTN4VlNWRlJKYTU3aFVLUDR5Y1lSVkplS0J1Wko3R2IxdkVYS3IxTHA2eC9kOW56LS1IbXlmelRlSWxiaG02Q3N2L0tUWHN3PT0=--b37c705a525ab2fb14feb5f2edf86d3ae1ab03c5"
(byebug) cookies.encrypted["_my_app_session"]
nil

Итак, сеанс nil в этот момент запроса:

(byebug) session
#<ActionDispatch::Request::Session:0x7ff41ace4bc0 not yet loaded>

Я могу принудительно загрузить сеанс с помощью

(byebug) session.send(:load!)

и когда я это сделаю, я вижу, что итоговый идентификатор сеанса

"f6be13fd646962de676985ec9bb4a8d3"

и, конечно, когда я позволю завершить запрос, то, что я вижу в представлении:

["session_id", "_csrf_token"] ["f6be13fd646962de676985ec9bb4a8d3", "qJ/aHzovZYpbrelGpRFec/cNlJyWjonXDoOMlDHbWzg="]

У меня также есть новое значение cookie, не связанное с тем, которое я редактировал.

Итак, из этого, я думаю, мы можем заключить, что происходит то, что, поскольку подпись cookie не может быть проверена, сеанс был аннулирован и регенерирован. Теперь у меня новый сеанс, с другим csrf_token.

Соответствующий код появляется в actionpack/lib/action_dispatch/middleware/cookies.rb:460-464, в классе EncryptedCookieJar:

def decrypt_and_verify(encrypted_message)
  @encryptor.decrypt_and_verify(encrypted_message)
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
  nil
end

Вместо дешифрования сообщения с недопустимой сигнатурой мы просто рассматриваем его как nil. Таким образом, недопустимый файл cookie, который хранит идентификатор сеанса и токен csrf, не используется для загрузки сеанса, и все, что зависит от значений в cookie, не будет выполнено.

Итак, почему мы не получили ошибку, а не только новый сеанс? Это потому, что мы не пробовали ничего, что зависит от зашифрованных значений. В частности, хотя мы имеем

protect_from_forgery with: :exception

(в отличие от :null_session) в ApplicationController, Rails не проверяет токен csrf в запросах GET или HEAD - он полагается на разработчика для реализации этих действий в соответствии со спецификацией, разрушительный. Если вы попробовали то же самое в запросе POST, вы получили бы ошибку ActionController::InvalidAuthenticityToken (как вы можете легко убедиться для себя).