Как защитить себя от фальсификации URL в Rails - PullRequest
1 голос
/ 27 января 2020

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

При просмотре задания (students/:id/assignments/:id) иногда меняют идентификатор назначения в URL-адресе на идентификатор задания, принадлежащего другому студенту. приводит к «ошибке метода» на моей странице assignments#show, в других случаях это покажет назначение другого студента, когда в идеале я бы хотел просто перенаправить обратно на их домашнюю страницу.

Аналогично, это происходит со страницей редактирования задания (students/:id/assignments/:id/edit), курсом (students/:id/courses/:id) и страницей редактирования курса (students/:id/courses/:id/edit). Иногда я получаю «ArgumentError in Assignments#edit» при просмотре страницы редактирования задания.

Я считаю, что это можно исправить в моих контроллерах, поэтому я включил мои assignments_controller и courses_controller.

Assignments_controller:

class AssignmentsController < ApplicationController
  before_action :require_logged_in
  before_action :set_student

  def new
    if @student && @student.id == current_student.id
      @assignment = Assignment.new
      @courses = Course.where(student_id: current_student.id)
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users assignments.'
    end
  end

  def create
    @assignment = Assignment.new(assignment_params)
    @assignment.student_id = current_student.id if current_student
    @courses = Course.where(student_id: current_student.id)

    if @assignment.save
      redirect_to student_assignments_path(@student)
    else
      render :new
    end
  end

  def index
    if @student && @student.id == current_student.id
      @assignments = Assignment.where(student_id: current_student.id)
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users assignments.'
    end
  end

  def show
    #student = Student.find_by(id: params[:student_id])
    if @student && @student.id == current_student.id
      #@assignment = student.assignments.find_by(id: params[:id])
      @assignment = Assignment.find_by(id: params[:id])
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users assignments.'
    end
  end

  def edit
    if @student && @student.id == current_student.id
      @assignment = Assignment.find_by(id: params[:id])
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users assignments.'
    end
  end

  def update
    student = Student.find_by(id: params[:student_id])
    @assignment = Assignment.find_by(id: params[:id])
    @assignment.update(params.require(:assignment).permit(:title, :due_date))
    redirect_to student_assignment_path(student, @assignment)
  end

  def destroy
    @student = Student.find_by(id: params[:student_id])
    @assignment = Assignment.find_by(id: params[:id]).destroy
    redirect_to student_path(@student), notice: 'Assignment was successfully completed.'
  end

  private

    def assignment_params
      params.require(:assignment).permit(:title, :due_date, :course_id, :student_id)
    end

    def set_student
      @student = Student.find_by(id: params[:student_id])
    end
end

Courses_controller:

class CoursesController < ApplicationController
  before_action :require_logged_in
  before_action :set_student

  def new
    if @student && @student.id == current_student.id
      @course = Course.new
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users courses.'
    end
  end

  def create
    if @student && @student.id == current_student.id
      @course = Course.create(course_params)
      @course.student_id = params[:student_id]

      if @course.save
        redirect_to student_courses_path(@student)
      else
        render :new
      end
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users courses.'
    end
  end

  def index
    if @student && @student.id == current_student.id
      @courses = Course.where(student_id: current_student.id)
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users courses.'
    end
  end

  def show
    @student = Student.find_by(id: params[:student_id])
    if @student && @student.id == current_student.id
      @course = @student.courses.find_by(id: params[:id])
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users courses.'
    end
  end

  def edit
    if @student && @student.id == current_student.id
      @course = Course.find_by(id: params[:id])
    else
      redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users courses.'
    end
  end

  def update
    student = Student.find_by(id: params[:student_id])
    @course = Course.find_by(id: params[:id])
    @course.update(params.require(:course).permit(:course_name))
    redirect_to student_course_path(student, @course)
  end

  def destroy
    @student = Student.find_by(id: params[:student_id])
    @course = Course.find_by(id: params[:id]).destroy
    redirect_to student_path(@student), notice: 'Course was successfully deleted.'
  end

  private

    def course_params
      params.require(:course).permit(:course_name)
    end

    def set_student
      @student = Student.find_by(id: params[:student_id])
    end
end

Ответы [ 4 ]

2 голосов
/ 28 января 2020

Эта строка является источником всех проблем:

@assignment = Assignment.find_by(id: params[:id])

Это огромная ошибка. Я бы сказал, что вы никогда, никогда не используете модель верхнего уровня для получения записей, которые должны быть защищены. Состояние сбоя этого кода - пользователь видит все. Эта проблема не может быть исправлена ​​путем исправления списка со списком контроля доступа. Они могут применяться неправильно каждый раз, кто-то может найти лазейку.

Вместо этого вы делаете это:

@assignment = @student.assignments.find_by(id: params[:id])

В худшем случае вы получаете ошибку «не найден». Невозможно обойти это, взломав URL. Состояние ошибки здесь: запись не найдена.

Если вы хотите, чтобы ваши URL-адреса были защищены от несанкционированного доступа, вам также следует использовать непоследовательные идентификаторы . На MySQL часто лучше всего создать дополнительный столбец специально для этой цели, например, под названием param или slug или ident, как вам угодно, и заполнить его чем-то случайным и безвредным, например:

 before_validation :assign_slug

 def assign_slug
   self.slug ||= SecureRandom.uuid
 end

Где это указано в вашей схеме для быстрого поиска. Если у вас есть отношения со студентом:

 add_index :assignments, [ :student_id, :slug ]

Postgres позволяет использовать первичные ключи UUID, которые могут быть многословными, но не позволяют людям возиться и экспериментировать для раскрытия информации. Вы действительно не можете «угадать» случайное значение UUID.

1 голос
/ 27 января 2020

Это может помочь вам:

В ваших CoursesController и AssignmentsController добавьте before_action в свои контроллеры, которые ограничат доступ студента.

#xxx_controller.rb
class XxxController < ApplicationController
  before_action :require_logged_in
  before_action :set_student
  before_action :check_owner, only: [:show, :edit, :update, :destroy]

Затем определите метод в вашем ApplicationController:

#application_controller.rb
def check_owner
  if @student.blank? || @student.id != current_student.id
    redirect_to student_path(current_student), error: 'Sorry, you can\'t view another Users assignments.'
  end
end
0 голосов
/ 27 января 2020

Итак, у вас настроена аутентификация, разрешающая доступ только зарегистрированным пользователям.

Теперь вам необходим процесс авторизации, чтобы разрешить доступ к определенным действиям / ресурсам в зависимости от идентификатора пользователя или роли.

Один из популярных вариантов - Pundit , и страница readme должна помочь вам начать работу.

0 голосов
/ 27 января 2020

Полагаю, вы ищете ограничение доступа. CanCanCan поможет вам правильно настроить доступ к страницам.

Также, пожалуйста, замените find_by(id: params[:id]) на find(id), потому что он более читабелен и эффективен.

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