对于我过去曾经做过的项目,我们将一个URL存储在应用程序数据库的一个字段中,这样当用户必须离开时,关闭他们的系统或其他什么,他们可以恢复工作打开受影响的记录。 此URL指的是在我们公开的Web API中为相关应用程序定义的Controller方法,并提供必要的参数来打开受影响的记录。
存在一个问题,我们注意到 - 很少 - 存储的端点是指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,以防止我们的应用程序陷入这种容易出错的状态。我们希望将此重定向发生在服务器端,不仅是出于安全原因,还因为它不是客户端代码问题。
我已就此主题进行了粗略的谷歌搜索,并且没有发现任何文章谈论如何对给定网址的动词进行反向工程。
问题:在给定一些网址的情况下,有没有办法确定哪些HTTP动词在C#中被引用?
如果不 - 我预计会出于安全考虑的原因 - 是否有任何关于避免此类问题的技术方面的建议?在发布此问题之前,我已对受影响的应用程序进行了代码审核,并且无法轻松重现导致此问题的条件(在我们的数据库中存储POST URL),并且未发现任何应导致此问题的逻辑POST URL将保存到我们的数据库中。
答案 0 :(得分:2)
任何URL都可以与任何HTTP动词一起使用,包括GET,POST,PUT,DELETE等。因此,无法推断仅给出URL的动词。
即使您可以弄清楚动词何时是POST,URL也不足以重新创建页面,因为POST需要保留在请求正文(而不是URL)中的信息。
听起来您的应用程序提供了一种服务器端的书签功能。如果目的是让用户从中断的地方继续,那么您有几个选择。
不是仅存储URL,而是存储完整的HTTP请求,包括动词和表单主体。如果任何值是特定于会话的(例如会话cookie),那么您将需要能够以某种方式替换那些新值。要非常小心,因为可能会出现无法预料的后果,例如:如果POST操作做了一些无法重复的事情。此外,存储身份验证中涉及的任何内容的POST请求(例如登录页面)是一个非常糟糕的主意。
不要将用户带回POST的目标,而是将用户带回发起POST的页面。一种方法是对所有处理POST的控制器进行编程,以验证表单变量;如果它们完全丢失,则重定向到用户应该填写的页面。
考虑让用户使用浏览器功能而不是服务器逻辑来管理自己的书签。
答案 1 :(得分:1)
因此,如果你正在使用某种行动过滤器,我们就是:
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...
}
......而且你已经确定了。