Реализация общих разделов (Новости, объявления, мероприятия, информационные страницы, галерея, библиотека)
На страницах новостей, объявлений, мероприятий и информационных страниц сценарий поведения пользователя схожий, в зависимости от прав он может: только просматривать содержимое (обычный пользователь), добавлять, изменять, удалять содержимое (привелигированный пользователь).
Для обычного пользователя все просто, он переходит по страницам и может посмотреть новости, объявления, текущие и запланированные мероприятия, просмотреть фотографии, но ничего изменить не может. Вся информация хранится в базе данных и перед тем как отобразить все это пользователю, содержимое проходит через функцию экранирования вывода, что является встроенной возможностью фреймворка.
Для пользователя, у которого есть возможность создавать, изменять новости, объявления, и т.д., необходимо осуществить фильтрацию всего пользовательского ввода, в связи с тем, что пользователь целенаправленно может внедрить исполняемый код. Наиболее распространенным языком для внедрения кода является клиентский скриптовый язык JavaScript. В фреймворке Ruby on Rails встроена автоматическая фильтрация пользовательского ввода.
Например, введенное пользователем
в содержимое новости, при сохранении в базу данных запишется как <script>alert('Hello!')</script>. При выборке и отображении пользователю, станет просто строкой
, которая, естественно, не исполнится, а просто отобразится.
Присутствует возможность пользователю загружать изображения в галерею, для логотипа новостей, или прикреплять к новости. Необходимо фильтровать имена файлов, в связи с тем, что злоумышленник может использовать злонамеренное имя файла для перезаписи любого файла на сервере. Эта проблема решена путем присваивания фотографиям собственных имен при загрузке на сервер.
def filename
"#{secure_token}.#{file.extension}" if original_filename.present?
End
def secure_token
var = :"@#{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end
Реализованный функционал можно посмотреть в Приложении 2 на следующих рисунках:
Рисунок . Новости;
Рисунок . Создание новости;
Рисунок . Объявления;
Рисунок . Информационная страница;
Рисунок . Мероприятия;
Рисунок . Создание мероприятия;
Рисунок . Организационная структура;
Рисунок . Телефонная книга;
Рисунок . Галерея;
Рисунок . Библиотека.
-
Реализация раздела «Предоставление расчетного листа»
Доступ к странице, предоставляющей информацию о расчетном листе сотрудника, проходит по следующему сценарию:
Пользователь должен пройти дополнительную аутентификацию, для этого он должен быть зарегистрирован в системе. (см. Приложение 2 Рисунок . Вход на сервис расчетных листов)
При успешной аутентификации ему отображается его расчетный лист и график выплат за выбранный период. (см. Приложение 2 Рисунок . Сервис расчетных листов)
При попытке входа пользователя на страницу расчетного листа происходит проверка на наличие сессии конкретного пользователя, в случае если сессии нет, то происходит переадресация на страницу аутентификации/регистрации/восстановления пароля.
def check_access_to_paysheet
unless current_user.id == session[:user_id]
redirect_to login_url
end
end
В момент использования пользователем услуги предоставления расчетного листа злоумышленнику может быть интересным «прослушивание» сетевого трафика. Заинтересовать его может пароль пользователя для доступа к листу, собственно информация, содержащаяся в листе, поэтому во время аутентификации и использования услугой расчетного листа необходимо использовать защищенное соединение.
При переходе пользователя на страницу для аутентификации/регистрации/восстановления пароля создается защищенное соединение, используя сертификат безопасности, подписанный центром сертификации в организации.
В контроллере вызывается метод redirect_to_https, производящий переадресацию на протокол https и блокируются вызовы методов redirect_to_http, являющийся обратным методу redirect_to_https.
skip_before_filter :redirect_to_http
before_filter :redirect_to_https
При регистрации пользователя происходит проверка на наличие согласия пользователя с условиями предоставления услуги: «Согласны ли вы использовать данный сервис для получения «Расчетного листка» через портал Филиала ООО «ЛУКОЙЛ – Инжиниринг» «КогалымНИПИнефть» в г. Тюмени?», необходимое присутствие пароля, контрольного вопроса и ответа на него, также минимальная длина, равная 6 символам и подтверждение пароля.
validates :agree, acceptance: true, allow_nil: false
validates :password, :question, :answer, presence: true
validates :password, length: { minimum: 6 }
validates :password, confirmation: true
Если проверка пройдена успешно, то происходит проверка на то, имеется ли уже пароль у пользователя, в случае если имеется, генерируется ошибка и пользователю не удается зарегистрироваться. Если нет пароля, то введенный пароль преобразуется с помощью функции SHA-256 с добавлением соли. Соль генерируется c помощью применения хэш-функции над текущим временем и случайным числом. Полученное преобразование пароля и соль пишутся в базу данных, в таблицу users, в поля encrypted_password и salt, соответственно.
def set_password
if password.present?
if encrypted_password.nil? || encrypted_password.empty?
self.salt = Digest::SHA256.hexdigest((Time.now + rand(10000)).to_s)
self.encrypted_password = Digest::SHA256.hexdigest("#{ salt }#{ password }")
else
errors.add(:encrypted_password, "У вас уже установлен пароль")
errors.blank?
end
end
end
Функция входа на сервис представляет собой сравнение преобразования от введенного пользователем пароля с имеющимся в базе данных.
def authenticate(password)
if encrypted_password == Digest::SHA256.hexdigest("#{ salt }#{ password }")
self
else
nil
end
end
После успешного входа на сервис, создается сессия, в нее пишется идентификатор текущего пользователя.
if current_user.authenticate(params[:password])
session[:user_id] = current_user.id
format.html { redirect_to paysheet_path }
В случае если пользователь забыл пароль, он может воспользоваться услугой восстановления пароля, ему необходимо будет ввести ответ на вопрос. В случае совпадения введенного ответа со значением, хранящимся в базе данных, будет сгенерирована ссылка, перейдя по которой сбросится пароль. Ссылка отправляется на корпоративную почту.
def send_reset_password
self.reset_password_token = SecureRandom.urlsafe_base64
self.reset_password_sent_at = Time.zone.now
save!(validate: false)
Notifier.delay.reset_password(id)
end
При переходе пользователя по этой ссылке проверяется соответствие ссылки со значением reset_password_token текущего пользователя. На возможность восстановления дается 1 день, после генерации ссылки.
if current_user.reset_password_token == params[:id] && params[:id] != nil
if current_user.reset_password_sent_at < 1.day.ago
flash[:alert] = "Время, отведенное для сброса пароля, вышло"
redirect_to controller: 'sessions', action:'new', formType: 1
else
current_user.reset_password
flash[:success] = "Пароль успешно сброшен"
redirect_to controller: 'sessions', action:'new', formType: 2
end
else
raise ActionController::RoutingError.new('Not Found')
end
Если вход осуществлен на сервис расчетных листов, создается подключение к другой базе данных, в которой хранятся сведения о расчетных листах пользователя. Для подключения к этой базе данных используется выделенный логин, имеющий право только на чтение. В эту базу данных данные экспортируются уже из бухгалтерской базы данных. В качестве параметров запроса используется табельный номер сотрудника и период времени. Отправляемые параметры фильтруются регулярным выражением и экранируются. Возвращаемые данные уже отображаются пользователю.
К критичным свойствам информации можно отнести только конфиденциальность, потому как изменение целостности и доступности информации не принесет никакого толка нарушившему, пользователю отобразится измененный, или не отобразится вовсе его расчетный лист, но он всегда может напрямую обратиться в Бухгалтерию, этот сервис сделан лишь для удобства пользователям.
|