代码之家  ›  专栏  ›  技术社区  ›  stevec Zxeenu

如何信任关联id参数?

  •  0
  • stevec Zxeenu  · 技术社区  · 4 年前

    下面是一个我们需要相信 conversation_id 未被用户更改:

    # messages_controller.rb
    def create
      @message = Message.new(
        body: message_params[:body], # trustworthy
        user_id: current_user.id, # trustworthy
        conversation_id: message_params[:conversation_id] # not trustworthy!
        )
      @message.save
    end
    

    所以我考虑用一个 if 像这样的声明

    # messages_controller.rb
    def create
      if current_user.conversations.pluck(:id).include? message_params[:conversation_id]
        @message = Message.new(
          body: message_params[:body], 
          user_id: current_user.id, 
          conversation_id: message_params[:conversation_id] 
          )
        @message.save
      end
    end
    

    这是我能想到的唯一方法来确保会话实际上是用户所属的会话(如果不仔细检查,可能会导致恶意用户成功地向其写入消息) 其他 人们的对话!)

    既然这种检查必须是相当普遍的,我只想知道我做了它的有效性和效率,还是有一个更好的方法或更多的'铁路方式'?

    我还应该补充一点,当消息不属于涉及用户的会话时,我可以对create方法进行保护(这应该完全防止自己的恶作剧),并且我在会话的\u id上使用了uuid(我知道这并不是真正的保护,但这都有帮助)。但我还是想知道,如果没有这些保护,我怎么能做到这一点,以便增加深度。

    1 回复  |  直到 4 年前
        1
  •  2
  •   max Mike Williams    4 年前

    实现这一点的方法是使用嵌套的路由,而不是通过 conversation_id 通过请求主体:

    resources :conversations do
      resources :messages, shallow: true
    end
    
    class MessagesController < ApplicationController
      # POST /conversations/:conversation_id/messages
      def create
        @conversation = current_user.conversations
                                    .find(params[:conversation_id])
        @message = @conversation.messages.new(message_params) do |m|
          m.user = current_user
        end
    
        if @message.save
          redirect_to @conversation
        else
          render :new
        end
      end
    
      private
      def message_parameters
        params.require(:message)
              .permit(:body)
      end
    end
    

    这是可行的,但还远远不够完美。如果 @conversation = current_user.conversations.find(params[:conversation_id]) 找不到一张唱片我们得到一张 ActiveRecord::RecordNotFound 异常和404响应,而不是检查用户是否有权发布到该对话。

    更好的解决方案是使用以下方法:

    @conversation = Conversation.find(params[:conversation_id])
    unless conversations.users.exist?(id: current_user.id)
      raise SomeKindOfAuthenticationError
    end
    

    当然,你真的应该使用类似权威的东西,而不是在这里重新发明轮子。