本文转自:http://book.51cto.com/art/200906/129770.htm
http://yeweiyun868.blog.163.com/blog/static/563784432011112985215397/
7.9.2 采用SSL实现加密传输(1)
在默认情况下,IIS使用HTTP协议以明文形式传输数据,Web Service就是使用HTTP协议进行数据传输的。Web Service传输的数据是XML格式的明文。没有采取任何加密措施,用户的重要数据很容易被窃取,如何才能保护网络中传递的这些重要数据呢?
SSL(Security Socket Layer)的中文全称是加密套接字协议层,它位于HTTP协议层和TCP协议层之间,用于建立用户与服务器之间的加密通信,确保所传递信息的安全性,同时SSL安全机制是依靠数字证书来实现的。
SSL基于公用密钥和私人密钥,用户使用公用密钥来加密数据,但解密数据必须使用相应的私人密钥。使用SSL安全机制的通信过程如下:用户与IIS服务器建立连接后,服务器会把数字证书与公用密钥发送给用户,用户端生成会话密钥,并用公共密钥对会话密钥进行加密,然后传递给服务器,服务器端用私人密钥进行解密,这样,用户端和服务器端就建立了一条安全通道,只有SSL允许的用户才能与IIS服务器进行通信。
注 意 SSL网站不同于一般的Web站点,它使用的是"HTTPS"协议,而不是普通的"HTTP"协议。因此它的URL(统一资源定位器)格式为"https://网站域名"。
下面讲解如何使用SSL来增强IIS服务器和Web Service的通信安全。
实现步骤如下。
1.为服务器安装证书服务
要想使用SSL安全机制功能,首先必须为Windows Server 2003系统安装证书服务。进入"控制面板",运行"添加或删除程序",接着进入"Windows组件向导"对话框,如图7-13所示。
图7-13 Windows组件向导 |
勾选"证书服务"选项,单击"下一步"按钮。
接着选择CA类型。这里选择"独立根CA"选项,如图7-14所示。单击"下一步"按钮,为自己的CA服务器起名,并设置证书的有效期限,如图7-15所示。
图7-14 选择CA类型 |
图7-15 设置CA信息 |
最后指定证书数据库和证书数据库日志的位置,如图7-16所示,单击"下一步"按钮。
图7-16 指定证书数据库 |
因为需要复制系统文件,所以需要插入Windows的安装光盘,如图7-17所示。安装证书服务需要停止当前的IIS运行,所以要单击"是"按钮。
图7-17 复制系统文件 |
最后,显示完成了证书服务的安装,单击"完成"按钮,如图7-18所示。
图7-18 安装完成 |
7.9.2 采用SSL实现加密传输(2)
2.配置SSL网站
1)创建请求证书文件
要想让Web Service使用SSL安全机制,首先需将Web Service配置为网站。然后为该网站创建请求证书文件。
依次单击"控制面板"→"管理工具"按钮,运行"Internet 信息服务(IIS)管理器",在管理器窗口中展开"网站"目录,用鼠标右键单击要使用SSL的Web Service网站,在弹出的快捷菜单中选择"属性"命令,在网站属性对话框中切换到"目录安全性"选项卡,如图7-19所示,
图7-19 网站属性 |
然后单击"服务器证书"按钮,弹出"IIS证书向导"对话框。
在"IIS证书向导"对话框中选择"新建证书"选项,单击"下一步"按钮,如图7-20所示。
图7-20 服务器证书 |
选择"现在准备证书请求,但稍后发送"选项。单击"下一步"按钮,如图7-21所示。
图7-21 证书向导 |
在"名称"输入框中为该证书取名,然后在"位长"下拉列表中选择密钥的位长(默认为1024,长度越长保密性越好,但性能会越差)。单击"下一步"按钮,如图7-22所示。
图7-22 设置证书名称 |
设置单位信息,如图7-23所示,然后单击"下一步"按钮。设置公共名称,如图7-24所示。
图7-23 设置单位信息 |
图7-24 设置公共名称 |
注 意 公共名称必须输入为访问站点的域名,例如要想用地址https://www.maticsoft.com访问Web Service,则此处必须填写为"www.maticsoft.com",否则将提示使用了不安全的证书,导致站点无法访问。并且切记,www.maticsoft.com和www.maticsoft.com:8001 带端口的访问也是不同的,如果设置的是www.maticsoft.com,则网站设置为www.maticsoft.com:8001来访问也是无法使用的。
然后,单击"下一步"按钮,设置国家地区,如图7-25所示。
图7-25 设置国家地区 |
设置证书的单位、部门、站点公用名称和地理信息,一路单击"下一步"按钮。
最后指定请求证书文件的保存位置。这样就完成了请求证书文件的创建。
7.9.2 采用SSL实现加密传输(3)
2)申请服务器证书
完成上述设置后,还要把创建的请求证书文件提交给证书服务器。
在服务器端的IE浏览器地址栏中输入"http://localhost/CertSrv/default.asp"。
在"Microsoft 证书服务"欢迎窗口中单击"申请一个证书"链接,如图7-26所示。
接下来在证书申请类型中单击"高级证书申请"链接,如图7-27所示。
图7-26 申请证书 |
图7-27 选择证书类型 |
然后在高级证书申请窗口中单击"使用base64编码的CMC或PKCS#10……"链接,如图7-28所示。
图7-28 选择编码 |
接下来在新打开的窗口中,打开刚刚生成的"certreq.txt"文件,将其中的内容复制到"保存的申请"中,如图7-29所示。
图7-29 提交证书申请 |
单击"提交"按钮,显示"证书挂起"页面,如图7-30所示。
图7-30 证书挂起 |
7.9.2 采用SSL实现加密传输(4)
3)颁发服务器证书
提交证书申请以后,还需要颁发服务器证书。依次选择"开始"→"设置"→"控制面板",双击"管理工具",再双击"证书颁发机构",在打开的对话框中选择"挂起的申请"选项,如图7-31所示。
(点击查看大图)图7-31 挂起的申请 |
找到刚才申请的证书,然后用鼠标右键单击该项,在弹出的快捷菜单中选择"所有任务"→"颁发"命令,如图7-32所示。
颁发成功后,选择"颁发的证书"选项,双击刚才颁发的证书,在弹出的"证书"对话框中的"详细信息"标签页中,单击"复制到文件"按钮,如图7-33所示。
图7-32 颁发证书 |
图7-33 复制到文件 |
弹出"证书导出向导"对话框,连续单击"下一步"按钮,选择"Base64编码X.509"选项,如图7-34所示。
(点击查看大图)图7-34 选择导出文件格式 |
单击"下一步"按钮,并在"要导出的文件"对话框中指定文件名,最后单击"完成"按钮。
4)安装Web服务器证书
重新进入IIS管理器的"目录安全性"标签页,单击"服务器证书"按钮,弹出"挂起的证书请求"对话框,选择"处理挂起的请求并安装证书"选项,单击"下一步"按钮,如图7-35所示。
(点击查看大图)图7-35 处理挂起的证书 |
指定刚才导出的服务器证书文件的位置,如图7-36所示。
(点击查看大图)图7-36 选择导出位置 |
接着设置SSL端口,使用默认的"443"即可,最后单击"完成"按钮。
7.9.2 采用SSL实现加密传输(5)
5)配置网站启用SSL通道
在网站属性"目录安全性"标签页中单击安全通信栏的"编辑"按钮,然后,勾选"要求安全通道(SSL)"选项,如图7-37所示。
(点击查看大图)图7-37 启用网站SSL通道 |
忽略客户端证书:选择该选项可以允许用户不必提供客户端证书就可访问该站点。
接受客户端证书:选择该选项可以允许具有客户端证书的用户进行访问,证书不是必需的。具有客户端证书的用户可以被映射;没有客户端证书的用户可以使用其他身份验证方法。
要求客户端证书:选择该选项则仅允许具有有效客户端证书的用户进行连接。没有有效客户端证书的用户被拒绝访问该站点。选择该选项从而在要求客户端证书前,必须选择"要求安全通道(SSL)"选项。
最后单击"确定"按钮,即完成启用SSL了。在完成了对SSL网站的配置后,用户只要在IE浏览器中输入"https://网站域名"就能访问该网站。
注 意
勾选上SSL后,必须用HTTPS来访问,而访问网站的端口也会使用SSL端口,默认为443。
如果在你访问站点的过程中出现无法正常访问的情况,那么请检查服务器防火墙是否禁止对SSl端口443的访问,这点比较容易被忽视,当然你也可以自己修改端口。
如果还是不能访问,出现提示"你试图从目录中执行 CGI、ISAPI 或其他可执行程序,但该目录不允许执行程序。HTTP错误403.1-禁止访问:执行访问被拒绝。"那么请检查网站主目录的执行权限,将执行权限设置为纯脚本即可,如图7-38所示。
图7-38 设置执行权限 |
6)客户端安装证书
如果IIS服务器设置了"要求客户端证书",则其他机器或用户想通过HTTPS访问和调用该Web服务,就需要将CA的根证书导入到客户端证书的可信任机构中,客户端才可以正常访问Web服务。
(1)选择"开始"→"运行"命令,在弹出的对话框中输入"mmc",出现如图7-39所示的界面。
图7-39 启动控制台 |
(2)选择"文件"→"添加/删除管理单元"命令,出现如图7-40所示的界面。
图7-40 添加/删除管理单元 |
(3)单击"添加"按钮,在可用独立管理单元列表中选择"证书"选项,出现如图7-41所示的界面。
(4)选择"计算机账户"选项,单击"下一步"按钮,选择"本地计算机"选项,然后依次单击"完成"→"关闭"→"确定"按钮。
图7-41 添加证书管理单元 |
进入当前用户的证书管理单元,界面如图7-42所示。
(点击查看大图)图7-42 选择证书导入位置 |
选中"个人"下的"证书节点"选项,单击鼠标右键,在弹出的快捷菜单中选择"所有任务"→"导入"命令,如图7-43所示。
(点击查看大图)图7-43 导入证书 |
选择我们刚才颁发的服务器证书cert.cer,将其导入到个人的存储位置,导入后如图7-44所示。
(点击查看大图)图7-44 导入到证书 |
7)SSL的优点与缺点
优点:它对Web服务提供的数据完整性没有任何影响,当值返回给客户时,值还是保持原样,并没有因在传输过程中使用了加密技术而发生变化。
缺点:它对站点的整体性能有影响,因为它需要进行很多加解密的数据处理。
7.9.3 访问IP限制
除了以上两种方式以外,还有一种比较简单的验证方式,就是通过对来源IP的检查来进行验证,我们只允许指定IP的服务器来访问,保证点对点的安全,我们可以在Web Service的方法中加入对IP的检查。
(示例位置:光盘codech07WebService1)
bool ValidateIP(int UserID, out string exceptionInfo)
{
exceptionInfo = "";
string uip = HttpContext.Current.Request.UserHostAddress;
Common dal = new Common();
List<string> ips = dal.GetPermitIp(UserID);//得到该用户ID所允许的IP列表
if (ips == null || ips.Count == 0)
{
exceptionInfo = "调用Web服务的客户端IP未被允许,无法访问!";
return false;
}
if (ips.Contains(uip)) //允许IP列表中包含该IP
{
return true;
}
exceptionInfo = "调用Web服务的客户端IP未被允许,无法访问!";
return false;
}
在具体Web方法里调用该方法检查用户访问者是否是以我们允许的IP进行访问的,以确保安全。
优点:简单,防止非指定客户机器访问。
缺点:IP是可以伪造的;维护IP地址表比较烦琐。且只适合于固定IP访问者的情况。
总之,上面几种方式只是一个简单的示例,讲解了怎样通过编程和配置的方式拒绝没有合法验证单据的客户端访问Web Service来保护你的Web Service。在你的安全模型中要求的复杂级别应该由你的商业需求决定。可以是一种或几种验证机制的组合。当然并不是所有的Web应用程序都需要上面的安全模式,尤其是当你的Web Service可以自由使用的时候,并不需要上面的安全机制处理。
7.10 Web Service开发中需要注意的问题(1)
1.接口是自说明的
接口的名字、参数和返回值应该一看就知道这接口大概是干什么用的。当然接口描述文档肯定是必需的,但这些描述文档的质量谁知道怎么样呢,谁有空天天翻着文档写东西呢,又有谁会背下来呢?所以让人眼前一亮的接口命名绝对值得,这也是所有代码书会告诉你应该遵守的一条规则。
2.服务接口粒度要合适
Web Service服务接口粒度太小了,那纯粹是不考虑XML解析性能了。一般新手容易犯这毛病,简单地把类的方法暴露出来做服务接口,这样其实是把原来在 local的调用放到了remote,除此之外几乎没有任何好处。粒度太大,会给使用者带来很多麻烦,因为在Web Service中,粒度很大的服务一般都需要很多参数来映射该服务各种各样的情况。
3.接口参数要尽量简单
只有一个参数的服务接口,往往不能满足业务需求。但过多的参数也提高了出错的几率,增加了测试的成本。所以,参数恰到好处为妙。
4.要提供对接口参数和返回值的校验
严格来说,对接口参数和返回值的验证也应该算是Web Service接口声明的一部分。增加对参数和返回值的校验,有利于减少调用者的疑惑,系统接受什么样的参数,返回值是什么格式都一目了然。但是这需要一个很好的权衡,否则调用者会觉得你暴露的方法很难用,因为限制太多了。比较理想的系统应该是宽进严出的,目标用户越多越应该注意这一点。要在宽进严出和全面校验之间做好平衡确实挺难的。简单的办法是,对要暴露的接口自己做测试,在测试的过程中体会这个度。一般来说如果自己感觉都不爽,那别人是绝对不会用的。
5.接口的返回值应该是简单的语言无关的
听见过很多人问如何返回DataSet之类的复杂类型,尤其是玩.NET的人,也许是VS.NET对封装DataSet提供了过于完美的支持吧。但对于XML来说,把任何复杂对象映射到XML文档都是困难的。就好比把三维向二维投影一样,复杂性增加了可不是一点半点。在XML中说到底所有的类型都是字符串,要想表达其他类型,就要添加额外的说明。可以看看rpc/encode方式WSDL文档的complexType部分,自行体会。
6.谨慎地抛出异常
对Web Service中的任何异常都应该进行相应的处理。可以简单地归纳为以下两种情况。
第1种情况是接口返回值是简单类型,比如bool型,就true和false两种情况,不抛出异常怎么办?选择有两种,一是抛出异常,二是改变接口,返回int用1和0对应true和false,用-1对应系统异常。
第2种情况是接口返回值是复杂对象,可以通过参数out string exceptionInfo来返回异常信息。
7.接口要尽量采用更新的标准
如何让一次定义的接口能服务得更好更久?从技术规范方面来说有两点:不超前,不落伍。超前,支持它的工具集不会太丰富,估计谁也不想弄出个看起来很美但是谁都用不了的东西;落伍,眼前所有的工具大概都支持,不过明天就不一定了,技术发展这么快,不能把自己累死吧。尽量采用更新的标准的意思是在不落伍的基础上要有前瞻性。举个简单的例子,今天再采用rpc/encode方式就显得不合时宜了,虽然它在前两年很流行,可今天都已经不提倡用了,明天说不定大家就都忘了。就算你及时更新了你的接口,客户也说不定已经换了供应商了。
8.要注意标准的通用性
虽然都是一样的标准,但标准有不同的版本,而且即使是同一个版本的标准,不同的工具实现起来也还是有细微差别的。如果用户是特定的还好说,采用些工具绑定的特性也没什么。但如果接口用户不是特定的人群,那就要注意了,在采用某一规范标准时不要用实现工具所特有的东西,否则很有可能造成客户的麻烦,导致只有很少一部分客户能使用你提供的接口。多一个客户就多一分钱啊,兄弟,干嘛跟钱过不去?
9.禁用HTTP POST/GET协议
除非另外指定,否则.NET将试图把Web服务绑定到3种协议:HTTP/POST、HTTP/GET和SOAP。之所以说"试图",是因为依赖于服务的参数和返回类型,HTTP/GET协议可能不可用。.NET生成的WSDL文件将自动包含绑定这3种协议的指令,客户程序可以自由选择使用哪种协议与服务通信。
只要在Web.config文件中加入下列内容,就可以删除对HTTP/POST和HTTP/GET协议的绑定:
<webServices>
<protocols>
<remove name="HttpPost" />
<remove name="HttpGet" />
</protocols>
</webServices>
为什么要避免通过HTTP/POST和HTTP/GET协议引出Web服务呢?主要的2个因素是安全性和互操作性。HTTP/GET的安全性不如SOAP,而且由于HTTP/GET常见于Web链接,怀有恶意的人可能利用它实施欺骗,使别人在不知不觉中用自己的安全标识调用Web服务,却还以为自己在单击Web链接。
就互操作性而言,SOAP是广泛应用的Web服务通信标准,而HTTP/GET和HTTP/POST不是。因此,对于.NET生成的WSDL文档中默认包含的HTTP/GET和HTTP/POST绑定,许多自动生成代理服务器的工具不会理解。因此,如果你的Web服务不是非绑定到HTTP/GET和HTTP/POST协议不可,最好取消这两种绑定。
7.10 Web Service开发中需要注意的问题(2)
10.用TcpTrace查看SOAP请求/应答消息
对于开发Web服务应用的人来说,调试可能是件异乎寻常的难事,因为无论是.NET SDK还是VS.NET,都没有提供工具来查看客户端和服务器之间的SOAP消息。
如果.NET和非.NET的客户端、服务器端的交互过程出现了问题,要想找出问题的根源,拥有查看SOAP消息的能力就尤为重要,因为这类问题往往与SOAP消息的格式有关(例如"消息中包含了SOAPAction吗?")。
tcpTrace(www.pocketsoap.com/tcptrace)是一个查看这类消息交换过程的优秀工具,它通过设置一个客户端和服务器端之间的隧道工作。启动tcpTrace时,它会要求输入目标URL和端口号,以及tcpTrace监听的本地端口号。这样,你就可以通过设置代理stub的URL属性,把stub指向这个本地端口(例如localhost:8080)。tcpTrace能够记录所有的请求和应答HTTP消息。
tcpTrace的一个局限是,它在消息流程中所处的位置决定了它不能用来查看通过SSL发送的消息。如果你要查看通过SSL发送的SOAP消息,只能编写一个定制的ISAPI过滤器。
11.简化接口设计
在众多有关N-层应用设计的论述中,简化接口设计这一设计要诀可以说是随处可见。但是,对于Web服务这样的分布式计算环境来说,简化接口设计的重要性更加突出。
在设计分布式应用时,出于性能和可伸缩性的考虑,应当保证客户端和服务器端之间的调用尽可能地少。减少网络调用不仅有利于减少通信开销(如果只用1个SOAP消息可以达到目标,就绝对不要发3个消息),降低网络流量,而且提高了应用的性能。显然,这一切都是开发者梦寐以求的目标。那么简化的接口到底有何特征呢?
首先来看一个复杂接口的例子:
namespace ChattyService
{
public class ChattyService : WebService
{
private string username;
private string password;
public string Username
{
[WebMethod]
set
{
username = Username;
}
}
public string Password
{
[WebMethod]
set
{
password = Password;
}
}
[WebMethod]
public bool Logon()
{
//验证身份
return true;
}
}
}
在这个例子中,username和password是两个属性,调用logon()方法之前首先必须设置这两个属性。有一个问题光看这段代码不太容易注意到,这就是username和password都作为Web方法引出。这就是说,每次对属性的get/set操作都会导致一个对服务的调用。
按照简化接口设计的要求,改进后的代码如下:
namespace ChattyService
{
public class ChattyService : WebService
{
[WebMethod]
public bool Logon(string Username, string Password)
{
//验证身份
return true;
}
}
}
现在,username和password成了logon()方法的参数。修改之后的代码的优点在于,它把登录操作对服务器的3次调用降低到了1次。另一方面,如果参数的个数太多,这个方法可能看起来很不像样。这时,可能要把方法的参数整理成几个复杂类型,例如,把username和password 两个参数封装到一个credential(证书)对象中。
12.避免使用ASP.NET会话状态
.NET实现的会话状态管理功能解决了它的前辈ASP 3.0存在的许多问题,例如请求串行化等,但仍存在一些局限。应当认识到,.NET的会话状态管理功能不是专门为Web服务环境中的会话状态而设计的,而是为了在范围更广泛的ASP.NET应用中管理会话状态而设计的,它依赖于HTTP Cookie(有一种通过改写URL实现的不需要Cookie的模式,但不适用于Web服务)。
Cookie是HTTP独有的。在Web上,所有的浏览器都支持HTTP,所以Cookie非常适合在Web应用中使用。但是,在Web服务中应用Cookie却把服务限定到了HTTP协议上。另一方面,SOAP协议的运行是独立于传输协议的,因此如果把Web服务应用限制到HTTP协议上,那么应用的灵活性也将受到限制,一旦要通过非HTTP的传输协议(例如SMTP)提供服务,事情就会变得很麻烦。