Web Api的安全性

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html

前言

这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议(http://),因此客户端与服务器之间的通信是没有加密的。在本篇中,我们将在“StudentController”中添加身份验证功能——通过验证用户名与密码来判断是否是合法用户。众所周知,对于机密信息的传递,我们应该使用安全的Http协议(https://)来传输

在Web Api中强制使用Https

我们可以在IIS级别配置整个Web Api来强制使用Https,但是在某些情况下你可能只需要对某一个action强制使用Https,而其他的方法仍使用http。

为了实现这一点,我们将使用Web Api中的filters——filter(过滤器)的主要作用就是可以在我们执行方法之前执行一段代码。没接触过得可以通过下图简单理解下,大神跳过:

我们新创建的filter将用来检测是否是安全的,如果不是安全的,filter将终止请求并返回相应:请求必须是https。

具体做法:创建一个filter继承自AuthorizationFilterAttribute,重写OnAuthorization来实现我们的需求。

在网站根目录下创建“Filters”文件夹,新建一个类“ForceHttpsAttribute”继承自“System.Web.Http.Filters.AuthorizationFilterAttribute”,下面上代码:

public class ForceHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var request = actionContext.Request; if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
var html = "<p>Https is required</p>"; if (request.Method.Method == "GET")
{
actionContext.Response = request.CreateResponse(HttpStatusCode.Found);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html"); UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);
httpsNewUri.Scheme = Uri.UriSchemeHttps;
httpsNewUri.Port = 443; actionContext.Response.Headers.Location = httpsNewUri.Uri;
}
else
{
actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
} }
}
}

在上面代码中,我们通过actionContext参数拿到request和response对象,我们判断客户端的请求:如果不是https,那么直接响应客户端应该使用https。

在这里,我们需要区分请求是Get还是其他(Post,Delete,Put),因为对于使用了Http的Get请求来访问资源,我们将使用https创建一个连接并添加在响应Header的Location中。这样做了之后客户端就会自动使用https来发送Get请求了。

对于非Get请求,直接返回404,并通知客户端必须使用https来请求

如果我们打算在整个项目中使用,那么在“WebAPIConfig”类中做如下设置:

public static void Register(HttpConfiguration config)
{
config.Filters.Add(new ForceHttpsAttribute());
}

如果我们相对具体的Controller或Action设置时,可以做如下设置:

//对于整个Controller强制使用Https
[Learning.Web.Filters.ForceHttps()]
public class CoursesController : BaseApiController
{
//仅对这个方法强制使用Https
        [Learning.Web.Filters.ForceHttps()]
public HttpResponseMessage Post([FromBody] CourseModel courseModel)
{ }
}

使用Basic Authentication验证用户

到目前为止,我们提供的所有Api都是公开的,任何人都能访问。但在真是场景中却是不可取的,对于某些数据,只有通过认证的用户才能访问,我们这里有两个地方恰好说明这一点:

1.当客户端发送Get请求道“http://{your_port}/api/students/{userName}“的时候.例如:通过上述URI访问userNme为“TaiseerJoudeh”的信息时,我们必须让客户端提供TaiseerJoudeh相应的用户名和密码,对于没有提供验证信息的用户我们就不让访问,因为学生信息包含一些重要的私人信息(email,birthday等)。

2.当客户端发送Post请求到“http://{your_port}/api/courses/2/students/{userName}“的时候,这意味着给学生选课,我们可以想一下,这里如果不做验证,那么所有人都能随便给某个学生选课,那么不就乱了么。

对于上面的场景,我们使用Basic Authentication来进行身份验证,主要思路是使用filter从请求header部分获取身份信息,校验验证类型是否为“basic”,然后校验内容,正确就放行,否则返回401 (Unauthorized)状态码。

在上代码前,解释一下下basic authentication:

什么是basic authentication?

它意味着在正式处理Http请求之前对请求者身份的校验,这可以防止服务器受到DoS攻击(Denial of service attacks)。原理是:客户端在发送Http请求的时候在Header部分提供一个基于Base64编码的用户名和密码,形式为“username:password”,消息接收者(服务器)进行验证,通过后继续处理请求。

由于用户名和密码仅适用base64编码,因此为了保证安全性,basic authentication通常是基于SSL连接(https)

为了在我们的api中使用,创建一个类“LearningAuthorizeAttribute”继承自System.Web.Http.Filters.AuthorizationFilterAttribute

public class LearningAuthorizeAttribute : AuthorizationFilterAttribute
{ [Inject]
public LearningRepository TheRepository { get; set; } public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//forms authentication Case that user is authenticated using forms authentication
//so no need to check header for basic authentication.
if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
return;
} var authHeader = actionContext.Request.Headers.Authorization; if (authHeader != null)
{
if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
!String.IsNullOrWhiteSpace(authHeader.Parameter))
{
var credArray = GetCredentials(authHeader);
var userName = credArray[0];
var password = credArray[1]; if (IsResourceOwner(userName, actionContext))
{
//You can use Websecurity or asp.net memebrship provider to login, for
//for he sake of keeping example simple, we used out own login functionality
if (TheRepository.LoginStudent(userName, password))
{
var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
Thread.CurrentPrincipal = currentPrincipal;
return;
}
}
}
} HandleUnauthorizedRequest(actionContext);
} private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader)
{ //Base 64 encoded string
var rawCred = authHeader.Parameter;
var encoding = Encoding.GetEncoding("iso-8859-1");
var cred = encoding.GetString(Convert.FromBase64String(rawCred)); var credArray = cred.Split(':'); return credArray;
} private bool IsResourceOwner(string userName, System.Web.Http.Controllers.HttpActionContext actionContext)
{
var routeData = actionContext.Request.GetRouteData();
var resourceUserName = routeData.Values["userName"] as string; if (resourceUserName == userName)
{
return true;
}
return false;
} private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized); actionContext.Response.Headers.Add("WWW-Authenticate",
"Basic Scheme='eLearning' location='http://localhost:8323/account/login'"); }
}

我们重写了“OnAuthorization”,实现如下功能:

1.从请求Header中获取校验数据

2.判断验证信息类型为“basic”并包含base64编码

3.将base64编码转化为string,并提取用户名和密码

4.校验提供的验证信息是否与访问的资源信息相同(学生的详细信息只能由他自己访问)

5.去数据库校验用户名及密码

6.如果校验通过,则设置Thread的CurrentPrincipal,使本次接下来的请求都是通过校验的。

7.校验没通过,返回401(Unauthorized)并添加一个WWW-Authenticate响应头,根据这个请求,客户端可以添加相应的验证信息

在代码中实现起来就很简单了,上两个Attribute就完了:

public class StudentsController : BaseApiController
{
[LearningAuthorizeAttribute]
public HttpResponseMessage Get(string userName)
{ }
}
public class EnrollmentsController : BaseApiController
{
[LearningAuthorizeAttribute]
public HttpResponseMessage Post(int courseId, [FromUri]string userName, [FromBody]Enrollment enrollment)
{ }
}

测试成果

使用测试工具发送如下请求:

由于没有提供身份验证,于是得到如下响应:

取消:

去数据库找到对应的用户名和密码输入,得到如下结果:

总结

因为 Base Authentication 的安全性较差,但对于无 Cookie 的 Web Api 来说,应用上非常的简单和方便。

Base Authentication 最大的缺点是凭据会被浏览器缓存——直到你关闭浏览器为止。如果你已经对某个URI获得了授权,浏览器就会在授权头发送相应的凭据,这使其更容易受到跨站点请求伪造(CSRF)攻击

Base Authentication 通常需要使用HTTPS方式进行加密处理。

源码地址:https://github.com/fzrain/WebApi.eLearning

Web Api的安全性的更多相关文章

  1. YbSoftwareFactory 代码生成插件【十三】:Web API 的安全性

    ASP.NET Web API 可非常方便地创建基于 HTTP 的 Services,这些服务可以非常方便地被几乎任何形式的平台和客户端(如浏览器.Windows客户端.Android设备.IOS等) ...

  2. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议 ...

  3. Web API 的安全性

    Web API 的安全性 ASP.NET Web API 可非常方便地创建基于 HTTP 的 Services,这些服务可以非常方便地被几乎任何形式的平台和客户端(如浏览器.Windows客户端.An ...

  4. [转]使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

    本文转自:http://www.cnblogs.com/fzrain/p/3552423.html 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html ...

  5. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  6. ASP.NET MVC View 和 Web API 的基本权限验证

    ASP.NET MVC 5.0已经发布一段时间了,适应了一段时间,准备把原来的MVC项目重构了一遍,先把基本权限验证这块记录一下. 环境:Windows 7 Professional SP1 + Mi ...

  7. Web API 使用上安全吗?

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  8. Web API入门指南(安全)转

    安全检测的工具站点:https://www.owasp.org/index.php/Category:Vulnerability_Scanning_Tools Web API入门指南有些朋友回复问了些 ...

  9. Web API 入门指南

    Web API 入门指南 - 闲话安全2013-09-21 18:56 by 微软互联网开发支持, 231 阅读, 3 评论, 收藏, 编辑 Web API入门指南有些朋友回复问了些安全方面的问题,安 ...

随机推荐

  1. hdu 4115 石头剪子布(2-sat问题)

    /* 意甲冠军:石头剪子布,目前已知n周围bob会有什么,对alice限制.供u,v,w:设w=0说明a,b回合必须出的一样 否则,必须不一样.alice假设输一回合就输了,否则就赢了 解: 2-sa ...

  2. Android使用surface直接显示yuv数据(三)

    在本文中,Java创建UI和关节JNI经营层surface直接显示yuv数据(yv12).发展环境Android 4.4,驰A23平台. package com.example.myyuvviewer ...

  3. 【Android界面实现】可旋转的汽车3D模型效果的实现

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 今天要给大家介绍的是怎样实现可旋转的汽车3D模型. 先看实现效果 这仅仅是静态图,实际上,这个模型是能够依据 ...

  4. JSON多层数据添加与访问

    最近项目中有要用到,JSON的多层数据对象,相当是一个json格式数组里面嵌套一个json对象吧,至于我为什么要用到这个呢,引入业务场景: 两组数据   1:    user_id    user_h ...

  5. C++拷贝构造函数具体解释

    一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是非常easy的,比如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各 ...

  6. 胖client和瘦client

    胖和瘦?纠结了妙龄少女,更郁闷了无数男女老少.每天充斥在宿舍的一句话就是:从明天開始我要减肥!!结果,可想而知,真的永远是明天而已.就这样,胖和瘦在我们人类之间无缝不在的存在着.但是client怎么就 ...

  7. c# p2p 穿透(源码加密)

    http://blog.oraycn.com/ESFramework_Demo_P2P.aspx 测试,完全OK!  我很喜欢这个.可以源码是加密的!我希望实现 web 版本的p2p视频观看,aehy ...

  8. HDU 5001 概率DP || 记忆化搜索

    2014 ACM/ICPC Asia Regional Anshan Online 给N个点,M条边组成的图,每一步能够从一个点走到相邻任一点,概率同样,问D步后没走到过每一个点的概率 概率DP  測 ...

  9. OC的构造方法与分类知识点总结

    OC语言构造方法: 用来初始化对象的方法,对象方法,以减号开头 为了让对象创建出来,成员变量就会有一些固定的值 重写构造方法的注意点: 先调用父类的构造方法([super init]) 再进行子类内部 ...

  10. APP-随身听

    简单到复杂听你的专属音响界,听金融.听物业,听新闻和其他节目专辑,简要介绍了新的音频应用,给你不一样的聆听体验.还记得老歌做?这里有.您留声机的一部分!很简单的音频应用,随时随地与此应用程序来听你的私 ...