加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

WebService的安全性讨论【身份识别】

发布时间:2020-12-17 01:19:34 所属栏目:安全 来源:网络整理
导读:http://www.aspxcs.net/HTML/0942423489.html# 相信很多开发者都用过WebService来实现程序的面向服务,本文主要介绍WebService的身份识别实现方式,当然本文会提供一个不是很完善的例子,权当抱砖引玉了. 首先我们来介绍webservice下的两种验证方式, 一.通过集

http://www.aspxcs.net/HTML/0942423489.html#

相信很多开发者都用过WebService来实现程序的面向服务,本文主要介绍WebService的身份识别实现方式,当然本文会提供一个不是很完善的例子,权当抱砖引玉了.

首先我们来介绍webservice下的两种验证方式,

一.通过集成windows身份验证

通过集成windows方式解决webservice的安全问题是一个很简洁,并且行之有效的解决方案,该方案的优 点是比较安全,性能较好,当然因为与windows紧密的结合到了一起,缺点自然也很明显了,第一,不便于移植,第二,要进行相关的配置部署工作(当然我 们也可以用代码来操作IIS,只不过比较麻烦,最近一直做自动化部署,所以一讲到配置马上就会联想到怎么去自动部署)

具体怎么做呢?

服务器端:配置IIS虚拟目录为集成windows身份验证

客户端:

  1. Service1?wr?=?new?Service1();?//web?service实例???
  2. ?
  3. wr.Credentials?=?new?NetworkCredential("administrator","123");?//用户名密码???
  4. ?
  5. lblTest.Text?=?wr.Add(2,2).ToString();?//调用Add的?web?service方法???

?

二.使用 SoapHeader(SOAP 标头)自定义身份验证

SoapHeader 多数情况下用来传递用户身份验证信息,当然它的作用远不止如此,有待于在实际应用中发掘,体可以实现哪些东西大家有想法可以留言一起交流.

SoapHeader 使用步骤:
(1) 创建继承自 System.Web.WebServices.SoapHeader 的自定义 SoapHeader 类型。
(2) 在 WebService 中创建拥有 public 访问权限的自定义 SoapHeader 字段。
(3) 在需要使用 SoapHeader 的 WebMethod 上添加 SoapHeaderAttribute 访问特性。SoapHeaderAttribute 构造必须指定 memberName 参数,就是我们在第二步中申明的字段名称。
(4) 生成器会自动为客户端生成同名的自定义 SoapHeader 类型,只不过比起我们在 WebService 端创建的要复杂一些。同时还会为代理类型添加一个 soapheaderValue 属性。

下面展示一段SoapHeader的代码,多余的方法将会在后面用到

客户端

  1. class?Program?
  2. ????{?
  3. ????????static?void?Main(string[]?args)?
  4. ????????{?
  5. ????????????Service1?ws?=?new?Service1();?
  6. ????????????ServiceCredential?mycredential?=?new?ServiceCredential();?
  7. ?
  8. ????????????mycredential.User?=?"gazi";?
  9. ????????????mycredential.Password="gazi";?
  10. ????????????ws.ServiceCredentialValue?=?mycredential;?
  11. ????????????string??mystr=ws.SayHello();?????????????
  12. ????????}?
  13. ????}?

服务器端

  1. public?class?Service1?:?System.Web.Services.WebService?
  2. ????{?
  3. ????????public?ServiceCredential?myCredential;?
  4. ?
  5. ????????[WebMethod]?
  6. ????????[SoapHeader("myCredential",?Direction?=?SoapHeaderDirection.In)]?
  7. ????????public?string??SayHello()??
  8. ????????{??
  9. ????????????return?"hello";?
  10. ????????}?
  11. ????}?
  12. ?
  13. ?
  14. ?
  15. public?class?ServiceCredential?:?SoapHeader?
  16. ????{?
  17. ????????public?string?User;?
  18. ????????public?string?Password;?
  19. ????????public?static?bool?ValideUser(string?User,string?Password)?
  20. ????????{?
  21. ????????????return?true;?
  22. ????????}?
  23. ????????public?static?void?CheckUser(Object?sender,?WebServiceAuthenticationEvent?e)?
  24. ????????{?
  25. ????????????if?(ValideUser(e.User,?e.Password))?
  26. ????????????{?
  27. ????????????????return;?
  28. ????????????}?
  29. ????????????else?
  30. ????????????{?
  31. ????????????????WebServiceAuthenticationModule?module?=?sender?as?WebServiceAuthenticationModule;?
  32. ????????????????module.Result.AddRule("验证错误",?"不能确认您的身份,请检查用户名和密码");?
  33. ????????????}?
  34. ????????}?
  35. ????}?

?

当我们拥有很多个类的时候,要添加一个或者删除一个验证方式(假设需要进行多种认证)是非常麻烦的,我们不可能跑到 每个方法里面去加一个方法调用,这是灾难性的工作,当然我们也可以用AOP来实现,Aop的话需要额外增加很多代码或者直接引入第三方来做,但是我们可不 可以有更简便的方法呢?

OK,答案就是使用HttpModule,我们集成IHttpModule写一个处理模块,那么它的原理是什么呢?具体进行了哪些操作呢?我们的思路如下:

  1. HTTP Module 分析 HTTP 消息以检查它们是不是 SOAP 消息。
  2. 如果 HTTP Module 检测到 SOAP 消息,它会读取 SOAP 标头。
  3. 如果 SOAP 消息的 SOAP 标头中有身份验证凭据,HTTP Module 将引发一个自定义 global.asax 事件。

下面来看看我们的Module代码

  1. public?class?WebServiceAuthenticationModule?:?IHttpModule?
  2. ????{?
  3. ????????private?static?WebServiceAuthenticationEventHandler?
  4. ??????????????????????_eventHandler?=?null;?
  5. ????????///?<summary>?
  6. ????????///?验证事件.绑定到此事件可进行对用户身份的识别?
  7. ????????///?</summary>?
  8. ????????public?static?event?WebServiceAuthenticationEventHandler?Authenticate?
  9. ????????{?
  10. ????????????add?{?_eventHandler?+=?value;?}?
  11. ????????????remove?{?_eventHandler?-=?value;?}?
  12. ????????}?
  13. ????????public?Result?Result?=?new?Result();?
  14. ?
  15. ????????public?void?Dispose()?
  16. ????????{?
  17. ????????}?
  18. ????????public?void?Init(HttpApplication?app)?
  19. ????????{?
  20. ????????????app.AuthenticateRequest?+=?new?
  21. ???????????????????????EventHandler(this.OnEnter);?
  22. ????????????Result.EndValid?+=?new??
  23. ????????????????EventHandler(this.OnCheckError);?
  24. ????????}?
  25. ?
  26. ????????///?<summary>?
  27. ????????///?验证用户身份?
  28. ????????///?</summary>?
  29. ????????///?<param?name="e"></param>?
  30. ????????private?void?OnAuthenticate(WebServiceAuthenticationEvent?e)?
  31. ????????{?
  32. ????????????if?(_eventHandler?==?null)?
  33. ????????????????return;?
  34. ?
  35. ????????????_eventHandler(this,?e);?
  36. ????????????if?(e.User?!=?null)?
  37. ????????????????e.Context.User?=?e.Principal;?
  38. ????????}?
  39. ?
  40. ????????public?string?ModuleName?
  41. ????????{?
  42. ????????????get?{?return?"WebServiceAuthentication";?}?
  43. ????????}?
  44. ?
  45. ????????void?OnEnter(Object?source,?EventArgs?eventArgs)?
  46. ????????{?
  47. ????????????HttpApplication?app?=?(HttpApplication)source;?
  48. ????????????HttpContext?context?=?app.Context;?
  49. ????????????Stream?HttpStream?=?context.Request.InputStream;?
  50. ?
  51. ????????????//?Save?the?current?position?of?stream.?
  52. ????????????long?posStream?=?HttpStream.Position;?
  53. ?
  54. ????????????//?If?the?request?contains?an?HTTP_SOAPACTION??
  55. ????????????//?header,?look?at?this?message.HTTP_SOAPACTION?
  56. ????????????if?(context.Request.ServerVariables["HTTP_SOAPACTION"]?==?null)?
  57. ????????????????return;?
  58. ?
  59. ????????????//?Load?the?body?of?the?HTTP?message?
  60. ????????????//?into?an?XML?document.?
  61. ????????????XmlDocument?dom?=?new?XmlDocument();?
  62. ????????????string?soapUser;?
  63. ????????????string?soapPassword;?
  64. ?
  65. ????????????try?
  66. ????????????{?
  67. ????????????????dom.Load(HttpStream);?
  68. ?
  69. ????????????????//?Reset?the?stream?position.?
  70. ????????????????HttpStream.Position?=?posStream;?
  71. ?
  72. ????????????????//?Bind?to?the?Authentication?header.?
  73. ????????????????soapUser?=?
  74. ????????????????????dom.GetElementsByTagName("User").Item(0).InnerText;?
  75. ????????????????soapPassword?=?
  76. ????????????????????dom.GetElementsByTagName("Password").Item(0).InnerText;?
  77. ????????????}?
  78. ????????????catch?(Exception?e)?
  79. ????????????{?
  80. ????????????????//?Reset?the?position?of?stream.?
  81. ????????????????HttpStream.Position?=?posStream;?
  82. ?
  83. ????????????????//?Throw?a?SOAP?exception.?
  84. ????????????????XmlQualifiedName?name?=?new?
  85. ?????????????????????????????XmlQualifiedName("Load");?
  86. ????????????????SoapException?soapException?=?new?SoapException(?
  87. ??????????????????????????"SOAP请求没有包含必须的身份识别信息",?name,?e);?
  88. ????????????????throw?soapException;?
  89. ????????????}?
  90. ????????????//?触发全局事件?
  91. ????????????OnAuthenticate(new?WebServiceAuthenticationEvent?
  92. ?????????????????????????(context,?soapUser,?soapPassword));?
  93. ????????????Result.OnEndValid();?
  94. ????????????return;?
  95. ????????}?
  96. ????????void?OnCheckError(Object?sender,?EventArgs?e)?
  97. ????????{?
  98. ????????????if?(Result.BrokenRules.Count?==?0)?
  99. ????????????{?
  100. ????????????????return;?
  101. ????????????}?
  102. ????????????else?
  103. ????????????{?
  104. ????????????????HttpApplication?app?=?HttpContext.Current.ApplicationInstance;?
  105. ????????????????app.CompleteRequest();?
  106. ????????????????app.Context.Response.Write(Result.Error);?
  107. ????????????}?
  108. ????????}?
  109. ????}?

?

Authenticate事件是一个静态的变量,这样我们可以在程序的外部来订阅和取消订阅事件(非静态的public 事件在外部也是不能进行订阅和取消订阅事件的,这也是事件和委托的一个区别之一)

下面是我们的事件参数以及委托

  1. public?delegate?void?WebServiceAuthenticationEventHandler(Object?sender,?WebServiceAuthenticationEvent?e);?
  2. ?
  3. ??///?<summary>?
  4. ??///?封装的事件参数?
  5. ??///?</summary>?
  6. ??public?class?WebServiceAuthenticationEvent?:?EventArgs?
  7. ??{?
  8. ??????private?IPrincipal?_IPrincipalUser;?
  9. ??????private?HttpContext?_Context;?
  10. ??????private?string?_User;?
  11. ??????private?string?_Password;?
  12. ?
  13. ??????public?WebServiceAuthenticationEvent(HttpContext?context)?
  14. ??????{?
  15. ??????????_Context?=?context;?
  16. ??????}?
  17. ?
  18. ??????public?WebServiceAuthenticationEvent(HttpContext?context,?
  19. ??????????????????????string?user,?string?password)?
  20. ??????{?
  21. ??????????_Context?=?context;?
  22. ??????????_User?=?user;?
  23. ??????????_Password?=?password;?
  24. ??????}?
  25. ??????public?HttpContext?Context?
  26. ??????{?
  27. ??????????get?{?return?_Context;?}?
  28. ??????}?
  29. ??????public?IPrincipal?Principal?
  30. ??????{?
  31. ??????????get?{?return?_IPrincipalUser;?}?
  32. ??????????set?{?_IPrincipalUser?=?value;?}?
  33. ??????}?
  34. ??????public?void?Authenticate()?
  35. ??????{?
  36. ??????????GenericIdentity?i?=?new?GenericIdentity(User);?
  37. ??????????this.Principal?=?new?GenericPrincipal(i,?new?String[0]);?
  38. ??????}?
  39. ??????public?void?Authenticate(string[]?roles)?
  40. ??????{?
  41. ??????????GenericIdentity?i?=?new?GenericIdentity(User);?
  42. ??????????this.Principal?=?new?GenericPrincipal(i,?roles);?
  43. ??????}?
  44. ??????public?string?User?
  45. ??????{?
  46. ??????????get?{?return?_User;?}?
  47. ??????????set?{?_User?=?value;?}?
  48. ??????}?
  49. ??????public?string?Password?
  50. ??????{?
  51. ??????????get?{?return?_Password;?}?
  52. ??????????set?{?_Password?=?value;?}?
  53. ??????}?
  54. ??????public?bool?HasCredentials?
  55. ??????{?
  56. ??????????get?
  57. ??????????{?
  58. ??????????????if?((_User?==?null)?||?(_Password?==?null))?
  59. ??????????????????return?false;?
  60. ??????????????return?true;?
  61. ??????????}?
  62. ??????}?
  63. ??}?

?

我们在Global.asax的Application_Start方法里面把前面介绍的静态方法ServiceCredential.CheckUser订阅到我们Authenticate事件上,前面提到的增加和删除多种认证方式就是通过这种方法实现的.

  1. protected?void?Application_Start(object?sender,?EventArgs?e)?
  2. ???????{?
  3. ???????????WebServiceAuthenticationModule.Authenticate?+=?ServiceCredential.CheckUser;?
  4. ???????}?

?

我们在ServiceCredential.ValideUser方法设置了返回false,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证 运行上面讲解SoapHeader的那段代码,你会发现我们的认证已经有效了.关于文章中用到的Result类改天在用一篇文章记录一下,这是一个非常好的记录错误的方案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读