За семь лет работы с Rails популярность фреймворка возросла, поскольку он позволяет быстро и легко создавать мощные приложения. Он легко решает многие проблемы, которые занимают время разработчиков, такие как интеграция баз данных, обработка сессий, рендеринг шаблонов и т. Д. Rails делает все это за нас.
Ну нет…
Rails предоставляет блестящую среду, которая дает нам строительные блоки для выполнения всех этих задач, но фактическая реализация зависит от нас, и очень легко отменить всю тяжелую работу Rails, если вы не знаете, что делаете. В этой серии статей я расскажу о том, как создать безопасный сайт в Rails, подчеркнув опасность доверия к данным и изучив передовые методы защиты ваших пользователей. Мы рассмотрим, как Rails защищает нас от потенциальных проблем, и как сделать вашу систему еще более надежной.
Серия разбита на три статьи:
- В этой статье я объясню некоторые способы, которыми хакеры могут манипулировать данными еще до того, как они достигнут вашего приложения, как Rails защищает нас от этих манипуляций и что вы можете сделать, чтобы защитить себя дальше.
- Далее мы еще немного углубимся в Rails и рассмотрим методы, которые вам нужно использовать, чтобы защитить себя, как только данные действительно попадут в ваше приложение.
- Наконец, мы рассмотрим рендеринг этих данных и другие вопросы безопасности Rails, о которых вам необходимо знать.
Это все о данных!
Веб-сайты все о данных. Данные поступают, сохраняются и передаются конечному пользователю. Худшая ошибка, которую вы можете совершить при создании сайта, — доверять этим данным. Не верь, откуда это; не верь, что это такое; и не верьте, как это будет выглядеть, когда вы это делаете. Создаете ли вы личный блог или большой сайт электронной коммерции, в тот момент, когда вы начинаете набирать популярность, кто-то попытается воспользоваться вами, и они, скорее всего, сделают это, манипулируя данными вашего сайта. использует.
Прежде чем мы начнем смотреть на то, как Rails решает эти проблемы, убедитесь, что ваша версия Rails актуальна. Rails — это библиотека, которую вы используете для создания своего сайта. В какой бы области разработки вы ни работали, важно использовать последние версии библиотек, поскольку они часто предоставляют важные обновления безопасности. В этой статье предполагается, что вы используете как минимум Rails 3.2.5. Если нет, то вам следует рассмотреть вопрос об обновлении немедленно.
Когда пользователь не пользователь?
У вас нет возможности узнать, откуда или откуда поступают данные, попадающие в ваше приложение. Это основополагающий принцип построения сайта. Аутентификация добавляет уровень безопасности, но у вас все еще нет гарантии, что запросы, попадающие на ваш сайт, поступают от аутентифицированного пользователя. Есть много способов, которыми хакеры могут маскироваться под пользователей, и вы обязаны помешать им сделать это.
Session Hijacking
Я пишу это, сидя в кафе. Я мог бы начать шпионить за сетевым трафиком всех остальных здесь за считанные минуты. Если URL вашего сайта начинается с «http: //» и кто-то входит на ваш сайт, я мог бы перехватить запрос на вход в систему и увидеть его пароли в текстовом виде. Единственный способ помешать мне сделать это — использовать HTTP Secure на этой странице входа, которая зашифрует трафик между пользователем и вашим сайтом. Если я слежу за пакетами, то увижу отправляемые данные, но не смогу их понять.
Это защищает учетные данные пользователей и является хорошим началом, но не защищает сеанс пользователя. Я мог бы просто подождать, пока наш восприимчивый любитель кофе войдет на ваш сайт, а затем перехватить и перехватить их аутентифицированную сессию, предоставив мне доступ к их учетной записи. Поэтому абсолютно необходимо зашифровать весь ваш сайт за https. Несколько лет назад это не поощрялось, потому что https был «дорогим» по времени обработки, кеширования и т. Д., Но теперь стало общепринятым, что безопасность важнее скорости. На самом деле, при использовании современных технологий дополнительное время, необходимое для шифрования, очень мало. На моих сайтах время загрузки страницы увеличивается на 20 мс. Я доволен этим компромиссом для безопасности моих пользователей.
Так как же это реализовать в Rails? Есть три вещи, которые вам нужно сделать. Во-первых, вам необходимо приобрести сертификат SSL и настроить свой веб-сервер для поддержки SSL. Если вы используете Heroku, у поддоменов herokuapp теперь есть SSL по умолчанию . Настройка SSL на вашем собственном домене проста и в основном включает две команды:
heroku addons:add ssl:endpoint | |
heroku certs:add my_cerficate.crt site.key |
Во-вторых, вам нужно указать, чтобы приложение Rails работало только по https. Rails делает это легко. Просто добавьте следующее в ваш блок config/application.rb
в config/application.rb
.
config.force_ssl = true |
Наконец, вы должны убедиться, что все ваши активы и ссылки являются https. Если у вас есть http-активы на странице https, браузер пользователя отобразит предупреждение о смешанном контенте на панели браузера. Как обычно, Rails выполняет большую часть работы за вас, но если у вас есть какие-либо жестко запрограммированные внутренние ссылки или изображения «http: //», обязательно измените их. Если у вас есть какие-либо размещенные вами сервисы (например, Typekit , внешние библиотеки javascript , управление внешними ресурсами через S3 и т. Д.), Убедитесь, что эти ссылки также являются https.
Одна заключительная мысль в отношении перехвата сеансов: убедитесь, что ваши сеансы истекают в разумные сроки, и что вы даете пользователям возможность выйти из системы. Если люди используют общедоступные или общедоступные компьютеры, последнее, что вам нужно, это то, чтобы злоумышленник появился через пять минут после того, как ваш пользователь ушел, и использовал свою учетную запись, поскольку сеанс все еще активен.
Хранение данных в сеансе
Существуют различные типы хранилищ сеансов, которые вы можете использовать в Rails. Начиная с версии v2 по умолчанию хранилище сессии сохраняется в файле cookie. Это быстро и хорошо масштабируется, но это означает, что вы должны быть очень осторожны с данными, которые вы храните по двум причинам. Во-первых, размер файлов cookie ограничен 4 КБ, поэтому, если вы храните в них слишком много данных, вы потеряете данные. Во-вторых, куки хранятся на стороне клиента, и поэтому данные, хранящиеся в течение сеанса, могут быть просмотрены. Rails включает хэш подписи SHA512 (засеянный секретной строкой, хранящейся на сервере), чтобы предотвратить подделку данных, но он не может остановить просмотр данных. Это означает, что если вы решите хранить конфиденциальные данные в сеансе, вы, в основном, представите их миру.
Для 99,99% приложений все, что вам нужно хранить в сеансе, это идентификатор пользователя. Это идеально подходит для файлов cookie и того, почему хранение файлов cookie используется Rails по умолчанию. Если у вас есть реальная, веская причина для хранения других данных в сеансе (и вам действительно нужно задаться вопросом, является ли эта причина достаточно обоснованной), выберите безопасный маршрут и сохраните данные сеанса в базе данных. Вы можете внести изменения в config/initializers/session_store.rb
:
Security::Application.config.session_store :active_record_store |
Вам также потребуется сгенерировать базу данных сеансов:
rails generate session_migration | |
rake db:migrate |
Атака Фиксации Сессии
Атаки фиксации сессии редки, но смертельны. Они включают в себя хакера, который настраивает сеанс (обычно это делается путем простого посещения сайта), а затем переопределяет cookie реального пользователя, чтобы они оба использовали один и тот же идентификатор сеанса. Как только реальный пользователь прошел аутентификацию (и, следовательно, этот сеанс аутентифицирован), хакер может получить доступ к сайту, как если бы он был настоящим пользователем. Руководство по безопасности Rails объясняет это более подробно.
Защититься от этих атак легко. Если вы используете сеансы для простого хранения user_id для целей аутентификации, то вы можете просто уничтожить сеанс и дать пользователю новый сеанс при входе в систему. Это мешает хакеру разделить сеанс с аутентифицированным пользователем. Чтобы достичь этого, просто добавьте это в свой контроллер сессий:
# Authenticate user | |
@user = #… | |
# Destroy the existing session in case anyone is sharing it and | |
# create a new session that you know to be unique to the user. | |
reset_session | |
# Store the user’s id as normal | |
session[:user_id] = @user.id |
Любые гемы аутентификации должны сделать это за вас, но важно, чтобы вы проверили, что делает ваш. Разновидность момента, Devise, защищена от атак фиксации сеанса начиная с версии 1.1.4 .
Атаки на межсайтовые запросы (CSRF)
Нападения CSRF были засвидетельствованы в дикой природе с начала века и невероятно опасны. Rails делает много работы для защиты от этих атак. Однако важно понимать, как работают атаки, и убедиться, что вы не ослабили им свое приложение.
CSRF-атака происходит, когда сторонний перенаправляет пользователя на деструктивный URL-адрес. Пример:
- В Twitter пользователи могут обновить свои профили с помощью запроса PUT по
http://www.twitter.com/settings/profile
. - Я размещаю ссылку на своем сайте, например:
<a href="http://www.twitter.com/settings/profile?_method=put&[email protected]">Win a million pounds<a>
. - Пользователь входит в Twitter, читает его последние твиты и уходит.
- Затем он посещает мой сайт, нажимает на мою специальную ссылку и при этом обновляет свой адрес электронной почты в Twitter.
- Теперь я захожу в твиттер, нажимаю ссылку «забытый пароль», в качестве адреса электронной почты указываю «[email protected]», получаю новый пароль в папке «Входящие» и получаю доступ к учетной записи пользователя.
Это плохо.
Чтобы избежать этого, Rails создает для сеанса «authenticity_token», который требуется для каждого не GET-запроса к серверу. Затем он молча вставляет этот токен в каждую форму, сгенерированную form_for
или form_tag
, в любые ссылки, имеющие method: "POST"
и т. Д., И в обратные вызовы Javascript с помощью ресурса jquery_ujs, который автоматически вставляется в ваш application.js. Если вы хотите увидеть пример этого, просмотрите источник страницы Twitter в моем примере, чтобы увидеть его на живом сайте. По умолчанию в вашем application_controller есть одна строка, содержащая: protect_from_forgery
. Это то, что говорит Rails проверять этот токен при каждом не GET-запросе. Только в самых необычных случаях вы должны удалить эту строку кода. Это сделает ваше приложение уязвимым для CSRF-атак.
Так что, если Rails сделает все это для вас, что вы должны сделать сами? Ну, есть две вещи, которые нужно сделать. Во-первых, вы должны убедиться, что если вы используете какие-либо внешние библиотеки Javascript, которые не используют jQuery для своих обратных вызовов AJAX, вы должны вручную вставить authenticity_token. Имя и значение токена хранятся в метатегах, поэтому вы можете создать URL-адрес следующим образом:
var form_data = //.. Serialise a form | |
// Get token and param from the meta tags | |
var token = $(‘meta[name=»csrf-token»]’).attr(‘content’); | |
var param = $(‘meta[name=»csrf-param»]’).attr(‘content’); | |
// Create url of «/settings/profile?name=Jeremy+Walker&authenticity_token=askdsalewg303y09sd00dshb0b00ac0dffbafds» | |
document.location = «/settings/profile?_method=PUT&» + form_data + «&» + token + «=» + param; |
Вторая вещь сложнее и заслуживает отдельного раздела.
Используйте RESTful Routes
Rails API дает нам ценную информацию о protect_from_forgery
:
Помните, что проверяются только запросы без GET, HTML / JavaScript.
Если вы создаете метод, который имеет какие-либо изменяющие или деструктивные свойства и доступ к нему можно получить с помощью запроса GET, у вас возникнут проблемы.
Допустим, мы создаем нашу собственную функциональность настроек. У нас есть контроллер и файл маршрутов следующим образом:
class SettingsController < ApplicationController | |
def show | |
@user = User.find(session[:user_id]) | |
end | |
def update | |
@user = User.find(session[:user_id]) | |
@user.update_attributes(params[:settings]) | |
end | |
end |
Security::Application.routes.draw do | |
match ‘show_settings’ => «settings#show» | |
match ‘update_settings’ => «settings#update» | |
end |
Ваше приложение теперь полностью открыто для атак CSRF. Я могу перенаправить пользователя на /[email protected]
и адрес электронной почты будет изменен. Если вы используете match
в своих маршрутах, тогда ваш код может быть уязвимым. Это такая большая проблема, что match
будет удалено из Rails 4, вместо этого вам потребуется указать методы в соответствии с:
Security::Application.routes.draw do | |
get ‘show_settings’ => «settings#show» | |
put ‘update_settings’ => «settings#update» | |
end |
Это лучше, но мы можем сделать еще лучше. Мы можем использовать RESTful маршруты, стиль Rails. Если мы рассматриваем настройки как ресурс, мы можем указать один и тот же URL для обоих маршрутов и определить функциональность, определенную методом. Так работает страница settings/profile
Twitter, о которой мы упоминали выше. Сделать это на вашем маршруте. Просто скажите rails, что вы работаете с ресурсом:
Security::Application.routes.draw do | |
resource :settings | |
end |
Теперь у нас есть один URL: /settings
, который мы можем использовать для просмотра или обновления наших настроек, используя GET или PUT. Rails ‘ protect_from_forgery
будет protect_from_forgery
, чтобы защитить нас от CSRF при отправке обновления PUT.
Не доверять никому!
Следуя приведенным выше советам, вы защитите своих пользователей от большинства известных угроз и гарантируете, что ваши запросы поступают из ожидаемого источника. Однако важно помнить, что даже если вы будете следовать всем этим советам, ваш сайт все равно будет уязвим. Хакеры всегда ищут следующий умный способ, чтобы воспользоваться вашим сайтом, и мы всегда пытаемся защитить себя.
В следующей статье мы еще немного углубимся в Rails и рассмотрим методы, которые нужно использовать, чтобы защитить себя, как только данные действительно попадут в ваше приложение. В третьей части мы рассмотрим рендеринг этих данных и другие вопросы безопасности Rails, о которых вам необходимо знать. А пока начните защищать ваше приложение …