0

设想:

  • 我没有 AJAX。
  • 我有一个带有GETmethod 和csrf_protectiondisabled 的搜索表单,用于过滤显示和分页的实体myEntityListAction,可通过 uri 访问/myapp/myentity/list
  • 用户打开/myapp/myentity/list,提交过滤表单并转到第 2 页。他现在在/myapp/myentity/list?entity_filter[search]=something&page=2
  • 用户打开另一个页面(假设显示的实体之一的详细信息),然后单击/myapp/myentity/list

我想让他看到页面/myapp/myentity//list?entity_filter[search]=something&page=2

我试图使过滤器粘到用户的会话中,这样当用户在/myapp/myentity/list没有任何参数的情况下重新打开时,他会得到最后一次看到的结果,具有相同的过滤器和页码。

我遵循了这种方法,但我认为它已被高度弃用,因为我正在修改$request对象和$_GET超全局(由于直接使用 $_GET 的分页库),尽管它有效。

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {
    if (0===$request->query->count()) { //querystring is empty
        $prev_query=$request->getSession()->get('my_entity_list', null);
        if ($prev_query) { //is there something in session?
            $_GET=$prev_query;
            $original_request=$request;
            $request=$request->createFromGlobals();
            $request->setSession($original_request->getSession());
        }
    } else { //i have something in my querystring
        $request->getSession()->set('my_entity_list', $request->query->all()); //i store it in session
    }
    //...do the other stuff (form, filters, pagination, etc)
}

我认为我将采用另一种方法,将用户重定向到/myapp/myentity/list?entity_filter[search]=something&page=2(从会话中读取),这样我就不必修改$_GET$request.

问题来了:如何在不进行重定向的情况下安全地编辑 $request 以注入或更改我需要的东西?我可以通过子请求安全地做到这一点吗?

4

2 回答 2

2

重新解释设置

您无法安全地编辑请求。不应在控制器内部修改请求,因为它是您将使用它的“最后一个地方”(即使您也可以在视图中使用它)。这并不安全。

重定向基于响应,而不是请求。

(奖励:让用户在会话中重置(或“清除”)此信息的好处。我建议您为此创建一个按钮。)

让我们重新解释一下您的(已经很好的)场景:

  • 第 1 步:
    用户/myapp/myentity/list
    在查询或会话中都没有。
    列表显示为应有的样子
  • 第 2 步:
    用户通过单击Page 2例如提交搜索表单
    表单提交使用户转到
    /myapp/myentity/list?entity_filter[search]=something&page=2
    一旦发出此请求,控制器将查询字符串保存在会话中作为“最后一次看到的查询字符串”,即my_entity_list您已经在使用的会话参数。
    使用过滤器按应有的方式显示列表
  • 第 3 步:
    用户/myapp/myentity/list通过单击徽标返回,例如
    “Nothing in query”。但是在会话中有一些东西。用户被重定向到/myapp/myentity/list?{last_query_string}
    然后返回步骤 2
  • 第 4 步:
    用户点击“清除过滤器”按钮。
    AJAX 或普通请求无关紧要:my_entity_list任何控制器都从会话中取消设置。
    将用户重定向到/myapp/myentity/list.
    返回步骤 1。

现在,代码

您的代码也必须用类似的东西重新组织:

/**
 * @Route("/myapp/myentity/list",  name="entity_list")
 * @Method({"GET"})
 */
public function myEntityListAction(Request $request) {

    // First, get query string
    $queryStringArguments = $request->query->all();

    if (0 === count($queryStringArguments)) {
        $lastQueryStringArguments = $request->getSession()->get('my_entity_list', null);

        if ($lastQueryStringArguments) {
            // Just replace the var, don't manipulate the request
            $queryStringArguments = $lastQueryStringArguments;
        }
    }

    // Whatever the var is retrieved from request or session,
    // this will always be saved in session.
    if (count($queryStringArguments)) {
        $request->getSession()->set('my_entity_list', $queryStringArguments); //i store it in session
    }

    //...do the other stuff (form, filters, pagination, etc)
}

最后,最佳实践

就您而言,您正在做的事情绝对不能安全注射。

您应该验证查询字符串并仅检索您需要的数据。

这可以通过一个FormType或简单的手动验证来完成,并且您应该取消设置所有不需要/未使用的查询字符串参数以避免潜在的注入。

使用类似$allowedParams = ['page', 'search_query', 'filter_by_id'];或类似的变量实现起来非常简单,并将帮助您重置不在此数组中的所有键(因此不要在会话中添加它们,也不要使用 html/javascript 注入操作表单)

于 2017-02-22T13:24:36.067 回答
1

您可以为此使用Before 过滤器。在侦听器中,检查您的会话,提取保存的路径(或过滤器)并使用类似的东西重定向(如果需要)

$event->setController(function() use ($redirectUrl) {
    return new RedirectResponse($redirectUrl);
});

您也可以使用获取请求$event->getRequest()并根据需要进行更改。

于 2017-02-22T13:17:17.213 回答