保护匿名Web API请求的方法

时间:2017-12-22 02:40:01

标签: c# asp.net asp.net-mvc

我有一个 ASP.NET MVC (非ASP.NET核心)单页面应用程序,前端有 angular js

我的客户端(浏览器)通过ASP.NET Web API与服务器通信。现在,网络应用程序位于 https ,但匿名。没有登录/用户身份验证。

Web应用程序采用向导的形式,用户可以来回移动并在网页上添加或更新输入字段。然后,通过Web API在服务器上更新表单输入值。

我正在寻找一种方法 安全 我的Web API调用,尤其是POST / PUT请求。总之,我想阻止任何用户直接从POSTMAN或Fiddler调用我的Web API。 Web API虽然是匿名的,但只能从发出请求的浏览器会话中调用。

  • 我有什么选择来实现这个目标?

  • 我可以在此处使用防伪标记(无需身份验证)吗?

  • 一种方法,我认为实现这一目的是为每个请求添加一个自定义标头,并在标头中存储某种会话密钥。然后,在我从客户端收到的每个请求上验证自定义标头。是否有其他方法可以实现这种开箱即用或经过验证的库而无需定制解决方案?

  • 如果我需要采用上述自定义解决方案,我需要注意哪些陷阱或潜在问题?

3 个答案:

答案 0 :(得分:6)

首先,当您删除登录并且您的应用程序中没有任何身份验证机制时,实际上无法保护任何内容,因为任何人都可以访问您的API。我想你想要的是确保你的API只能从你自己的网站上调用。遗憾的是,您无法完全实现这一点,因为您的网络API是http / https,任何人(如邮递员,小提琴手......)都可以创建http请求并调用您的API。

您所能做的就是让API更难以响应请求,例如您提到的使用Anti-Forgery。

我还建议你为你的应用程序添加一个cookie,并在每个请求中检查cookie,在这种情况下,使用Fiddler或Postman调用你的API会更复杂(并非不可能)。

最后我建议您使用CORS,因此浏览器只允许您的域名调用您的API。因此,没有人可以在不同域的浏览器中调用您的API。

答案 1 :(得分:3)

根据@Arvin的回答和@Evk的评论,以下是我打算如何继续:

  • 一旦用户启动anonymous会话,使用常规Guid.NewGuid()方法生成GUID并将其保存在DB中以识别请求(我现在正在执行此操作)。但是,如上所述here
  

GUID可以是唯一的,但它们不受加密保护。

  • 因此,不使用纯文本GUID,而是使用当前时间戳token对其进行加密,并将其附加到请求查询字符串。

  • 对于每个后续API请求,请从查询字符串中读取token,对其进行解密并按如下方式对其进行验证:

    • 检查时间戳。如果时差大于预定义时间(即令牌已过期),则拒绝请求

    • 根据数据库验证唯一ID(GUID)

  • 因为我不再使用纯文本GUID,所以URI不容易猜到。

此外,使用时间戳,URI会在某段时间后失效。虽然理论上仍然可以通过Fiddler调用API,但这对攻击者来说应该是非常困难的,如果不是不可能的话。

  • 作为进一步的安全措施,我还可以在请求中添加Anti-Forgery令牌

根据我的理解,这有助于解决我的潜在问题,通过这种方法,我甚至可能不需要添加cookie来保护我的匿名会话。

如果这种方法看起来很好并且如何改进,那么很想听听大家的意见。

答案 2 :(得分:2)

我曾经有过在WebAPI上拥有会话功能的奇怪需求,并创建了一个完全符合您目标的OWIN会话中间件。

该库名为 OwinSessionMiddleware ,可在githubNuGet上使用。

<强>用法

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseSessionMiddleware();

        // other middleware registrations...
        app.UseWebApi();
    }
}

您还可以传递一些options以进一步调整cookie名称,添加数据库支持的会话存储(而不是内存中),添加您自己的会话ID生成器(而不是基于的默认id生成器)由RNGCryptoServiceProvider生成的GUID +安全随机部分。

唯一会话ID本身存储为安全cookie,中间件会在每次请求时自动恢复会话。

您可以在API控制器内调用extension methods来获取和设置会话数据:

public SomeApiController : ApiController
{
    public IHttpActionResult MyAction()
    {
        var requestCount = Request.GetSessionProperty<int>("RequestCount");

        Request.SetSessionProperty("RequestCount", ++requestCount);
    }
}