【问题标题】:Determine the HTTP verb of an endpoint based on the URL根据 URL 确定端点的 HTTP 动词
【发布时间】:2017-04-12 19:02:51
【问题描述】:

对于我过去从事的一个项目,我们将一个 URL 存储在应用数据库的一个字段中,以便当用户不得不离开、关闭系统或其他任何事情时,他们可以恢复工作通过打开受影响的记录来处理某事。 此 URL 指的是在我们公开的 Web API 中为相关应用程序定义的控制器方法,并提供了打开受影响记录所需的参数。

有一个问题,我们注意到 - 很少 - 正在存储的端点是指 POST 端点,而不是 GET 端点。当这个条件被触发时,我们会得到如下异常:

The parameters dictionary contains a null entry for parameter 'MyParameter' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult SomeEndpoint(Int32, Int32)' in 'MyApplication'.  An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

我们知道要解决问题要做什么:我们要扫描 URL 并确定动词。如果动词是 POST,我们希望重定向到特定的 URL,以防止我们的应用程序陷入这种容易出错的状态。我们希望在服务器端进行这种重定向,不仅出于安全原因,而且因为它根本不是客户端代码问题。

我在 Google 上对此主题进行了粗略的搜索,但没有找到任何有关对给定 URL 的动词进行逆向工程的文章。

问题:有没有什么方法可以在给定一些 URL 的情况下确定在 C# 中引用的 HTTP 动词是什么

如果有没有——这是我所期望的,很可能是出于安全原因——是否有任何关于避免此类问题的技术建议?在发布这个问题之前,我已经对受影响的应用程序进行了代码审计,并且无法轻松地重现导致这个问题的条件(在我们的数据库中存储一个 POST URL),并且没有发现应该导致的逻辑一个 POST URL 被保存到我们的数据库中。

【问题讨论】:

  • 您几乎必须使用动词调用 url 以查看它是否有效。虽然名字没有规则,但有约定,所以你大概可以根据名字直觉一些人用的是什么动词。

标签: c# rest asp.net-web-api httpverbs


【解决方案1】:

任何 URL 都可以与任何 HTTP 动词一起使用,包括 GET、POST、PUT、DELETE 等。因此,仅给定 URL 就无法推断动词。

即使您可以确定动词何时是 POST,URL 也不足以重新创建页面,因为 POST 需要请求正文(而不是 URL)中保存的信息。

听起来您的应用程序提供了一种保存在服务器端的书签功能。如果目的是让用户从他们离开的地方继续,你有几个选择。

  1. 不要只存储 URL,而是存储完整的 HTTP 请求,包括动词和表单正文。如果任何值是特定于会话的(例如会话 cookie),那么您将需要能够以某种方式替换新值。对此要非常小心,因为可能会产生无法预料的后果,例如如果 POST 操作做了一些不能重复的事情。此外,存储涉及身份验证的任何内容(例如登录页面)的 POST 请求也是一个非常糟糕的主意。

  2. 不是将用户带回 POST 的目标,而是将用户带回发起 POST 的页面。一种方法是对所有处理 POST 的控制器进行编程以验证表单变量;如果它们完全丢失,请重定向到用户应该填写的页面。

  3. 考虑让用户管理他或她自己的书签,使用浏览器功能而不是服务器逻辑。

【讨论】:

  • 旁注:重放 POST 或任何其他非 GET 请求(选项 1)可能会失败或至少使系统进入未定义状态,因为站点很少期望重试 POST(即重放 POST删除表的行几乎肯定会失败)
  • 听起来我的怀疑——“简单”的方式不存在——是正确的。我会考虑设计中的其他可能性。它可能就像使用将 URL 存储在数据库中的过滤器来存储调用它的动词一样简单。可能是别的东西。不过,这给了我一个起点。谢谢!
【解决方案2】:

所以,如果您使用某种动作过滤器,就像我们一样:

public class SomeActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CacheCurrentStep(filterContext.HttpContext.Request);
    }

    private static void CacheCurrentStep(HttpRequestBase request)
    {
        string url = request.Url.PathAndQuery;
        // Save it, however you do that
    }
}

...可以通过嗅探请求获取代理动词!

private static void CacheCurrentStep(HttpRequestBase request)
{
    if(request.HttpMethod.ToUpper() != "GET")
        return;

    string url = request.Url.PathAndQuery;
    // Save it, however you do that
}

HttpRequest 类有一个公开的HttpMethod 属性,该属性返回 HEAD、GET 或 POST。 HttpRequest上有一个相关的属性RequestType,它只返回GET或POST,可以代替使用。

对于任何从未使用过动作过滤器的未来读者,您只需使用属性注释控制器...

[SomeAction]
public class MyApiController : ApiController
{
    // Endpoints...
}

...你准备好了。

【讨论】:

    猜你喜欢
    • 2013-02-10
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    相关资源
    最近更新 更多