启用和自定义 ASP.NET Web API 服务的安全性

对于最常见的场景 — Web 页面中的 JavaScript 访问同一站点上的 Web API 服务,讨论 ASP.NET Web API 的安全性几乎是多余的。如果对用户执行身份验证和授权对 Web 窗体/视图(包含使用服务的 JavaScript)的访问均已设置,则服务可能已具备其所需的所有安全性了。这要归因于 ASP.NET,它会将其用 于验证页面请求的 Cookie 和身份验证信息作为对服务方法的任意客户端 JavaScript 请求的一部分进行发送 。但有一个非常重要的例外: ASP.NET 无法自动防御跨站点请求伪造 (CSRF/XSRF) 攻击(稍后详述)。

除 CSRF 以外,还有两个值得探讨 Web API 服务保护的场景。第一个场景是当服务的使用方为客户端,而 非与 ApiControllers 处于同一个站点上的页面时。这些客户端可能未经过窗体身份验证的审核,也可能未获 取 ASP.NET 用于控制服务访问的 Cookie 和令牌。

第二个场景是需要为服务添加超出 ASP.NET 安全功能范围的身份验证时。ASP.NET 提供的默认身份验证基 于在身份验证期间 ASP.NET 分配给请求的标识。您可能希望扩展该标识,以授权进行基于标识名称或角色以 外条件的访问。

Web API 提供了多种选择,以应对这两种场景。事实上,我将讨论的是接受 Web API 请求上下文的安全性 ,但由于 Web API 与 Web 窗体和 MVC 均以 ASP.NET 为基础,因而了解 Web 窗体或 MVC 安全性的读者一定 会非常熟悉本文中介绍的工具。

有一点需要特别注意: 虽然 Web API 提供了多种身份验证和授权选项,但安全始于主机(IIS 或进行自 托管时创建的主机)。例如,如果需要确保 Web API 服务与客户端之间通信的隐秘性,则至少应开启 SSL。 但这是站点管理员而非开发者的职责。在本文中,我将忽略主机方面的内容,专注于开发者能够/应该为确保 Web API 服务的安全而进行的工作(无论 SSL 开启与否,我讨论的这些工具都能正常工作)。

抵御跨站点请求伪造攻击

当用户访问使用窗体身份验证的 ASP.NET 网站时,ASP.NET 会生成一个 Cookie,表明该用户已经过身份 验证。浏览器会在每次向该站点发出后续请求时发送该 Cookie,而不管请求来自何处。只要会导致浏览器自 动发送之前收到的身份验证信息的任意身份验证方案存在,您的站点就有可能成为 CSRF 的攻击目标。在站点 向浏览器提供安全 Cookie 后,如果用户访问了某个恶意站点,该站点即可向您的服务发送请求,利用浏览器 之前收到的身份验证 Cookie 发动攻击。

为抵御 CSRF 攻击,需要在服务器端生成防伪令牌,并将之嵌入到要在客户端调用中使用的页面中。 Microsoft 提供了 AntiForgery 类及一个 GetToken 方法(可生成特定于发出请求的用户的令牌,当然,此 处的用户可以为匿名用户)。下面的代码生成了两个令牌,并将之嵌入至可在 View 中使用的 ASP.NET MVC ViewBag:

          [Authorize(Roles="manager")]
public ActionResult Index()
{
  string cookieToken;
  string formToken;
  AntiForgery.GetTokens(null, out cookieToken, out formToken);
  ViewBag.cookieToken = cookieToken;
  ViewBag.formToken = formToken;
  return View("Index");
}

针对服务器的任意 JavaScript 调用都需要将该令牌作为请求的一部分予以返回(CSRF 站点没有 此类令牌,也就无法返回它们)。下面的代码(位于 View 中)将动态生成一个将令牌加入请求标题中的 JavaScript 调用:

        $.ajax("http://phvis.com/api/Customers",{
type: "get",
contentType: "application/json",
headers: {
  'formToken': '@ViewBag.formToken',
  'cookieToken': '@ViewBag.cookieToken' }});

一个稍微复杂点的解决方案是将令牌嵌入至 View 中的隐藏字段,使得这段 JavaScript 代码不会太引人注目。该过程的第一步是将令牌添加到 ViewData 字典 中:

          ViewData["cookieToken"] = cookieToken;
ViewData["formToken"] = formToken;
接下来,在 View 中将数据嵌入至隐藏字段。使用 

HtmlHelper 的 Hidden 方法时,只需传递 ViewDate 中的某个键值,以生成正确的输入标记:
@Html.Hidden("formToken")

生成的输入标记将使用 ViewData 键作为标记的名称和 ID 属性 ,并将从 ViewData 字典检索到的数据放入标记的值属性中。之前代码生成的输入标记将如下所示:

<input id="formToken" name="formToken" type="hidden" value="...token..." />

之后,即可用 JavaScript 代码(跟 View 保存在不同的文件中)从输入标记中检索值并在 ajax 调用中使用 它们:

        $.ajax("http://localhost:49226/api/Customers", {
type: "get",
contentType: "application/json",
headers: {
  'formToken': $("#formToken").val(),
  'cookieToken': $("#cookieToken").val()}});

在 ASP.NET Web 窗体中,通过使用 ClientScriptManager 对象(可从 Page 的 ClientScript 属性检索)的 RegisterClientScriptBlock 方法 插入包含嵌入式令牌的 JavaScript 代码,也可达到同一目的。

          string CodeString = "function CallService(){" +
  "$.ajax('http://phvis.com/api/Customers',{" +
  "type: 'get', contentType: 'application/json'," +
  "headers: {'formToken': '" & formToken & "',” +
  "'cookieToken': '" & cookieToken & "'}});}"
this.ClientScript.RegisterClientScriptBlock(
  typeOf(this), "loadCustid", CodeString, true);

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript
, web api
, 验证
, 请求api
, 窗体
, 令牌
, 服务
, viewbag
, 身份
, asp net mvc 跨控制器
, api asp.net MVC 
, asp.net web api
启用Csrf
,以便于您获取更多的相关知识。

时间: 2024-12-30 07:03:29

启用和自定义 ASP.NET Web API 服务的安全性的相关文章

asp.net web api get请求能在主体中包含自定义对象吗

问题描述 asp.net web api get请求能在主体中包含自定义对象吗 大家好,我的问题是我现在想提供一个判断服务接口,就是客户端传给我一个人的id 和此人的照片(20K左右),我这边接收然后判断并返回结果{result:1}或者{result:0}, 本人刚接触asp.net web api,没有经验,我想用Get方法来解决这个问题,我开始把 参数都放在URI中,接收的照片数据长度不足,于是我想把参数组成一个自定义对象放 在请求消息主体里面,请问怎么才能实现呢,非常感谢你的耐心,谢谢帮

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【外传】——Attribute Routing

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[外传]--Attribute Routing 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 题外话:由于这个技术点是新学的,并不属于原系列,但借助了原系列的项目背景,故命名外传系列,以后也可能在这个系列中附加一些新的技术. 前言 在Web Api 2.0中,提出了一种新的配置路由方式--基于特性的路由(Attribute-based Routing),在我们之前

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[四]--实现模型工厂,依赖注入以及格式配置 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在上一篇中,我们已经初步开始使用Web Api了,但同时出现了一些很多不足之处,本章我们就着重来解决这些不足. 上篇导航:http://www.cnblogs.com/fzrain/p/3510035.html 配置JSON的格式 Web Api提供Xml和JSON作

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[十]--使用CacheCow和ETag缓存资源 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的缓存. 使用缓存技术可以很好的提高Web Api的性能,减小服务器的开销.我们把这种缓存形式称之为:条件化请求(Conditional Requests).具体表现为:客户

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[开篇][持续更新中...] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tutorial-building-asp-net-web-api-restful-service/.于是打算跟着学一下,把学习过程记录在博客园的同时也分享给大家. 每一篇结束后我都会把代码共享 由于

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【三】——Web Api入门

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[三]--Web Api入门 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 经过前2节的介绍,我们已经把数据访问层搭建好了,从本章开始就是Web Api部分了.在正式开始之前,再一次回顾一下Web Api的应用场景:Web Api可以与 MVC,WebForm结合使用,也可以作为一个单独的Web服务.在正式讨论Web Api的配置以及如何构造我们的URI来消

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[七]--实现资源的分页 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这篇文章我们将使用不同的方式实现手动分页(关于高端大气上档次的OData本文暂不涉及,但有可能会在系列的后期介绍,还没确定...),对于分页的结果,我们将采用2种不同的方式响应给客户端(1.将分页元数据封装在响应Body中2.在http响应报文头部添加分页信息). 众所周知,在服务器端一

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[五]--在Web Api中实现Http方法(Put,Post,Delete) 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现--Post(新增),Put(修改),Delete(删除),Get(查询).查询在前几章我们已经实现了,本章就在我们的案列(CourseController)

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【六】&amp;mdash;&amp;mdash;实现资源间的关联

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[六]--实现资源间的关联 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章主要介绍一下资源间的关联--例如在学生和课程之间就存在这样的关联:每一个课程都会有多个学生来选,如何获取这些有关联的信息?如何实现选课的业务?对于客户端应该怎么来调用呢?下面给出解决方案: 配置对应的路由 对于上面的需求,我们可以先定制一个URI模板:"api/courses