`
zhb8015
  • 浏览: 375965 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
Spring Roo杂谈
浏览量:0
社区版块
存档分类
最新评论

转:浅析http平台的安全稳定性架构

    博客分类:
  • java
阅读更多

原文地址:http://chenkangxian.iteye.com/blog/1819885

 

--转载自己的文章,原文发表在《程序员》2013年第2期上,感谢《程序员》授权转载

前言:随着移动互联网的兴起以及restfulweb service的大规模使用,http协议因其使用方便以及跨平台的特性,在web开发以及SOA领域得到了广泛使用。但其所涵盖的信息,大都是未经加密的明文,信息获取门槛的降低,也为应用架构的安全性及稳定性带来了挑战。

 

对于常规的web攻击手段,如xsscrsfsql注入等等,防范措施相对来说也比较容易,比如xss的防范需要转义掉输入的尖括号,防止crsf需要将cookie设置为httponly以及增加session相关的hash token码, sql注入的防范需要将分号转义等等,做起来虽然简单,但却容易被忽视,更多的是需要从开发流程上来予以保障,以免因人为的疏忽而造成损失。

 

本篇更多的是从平台架构的安全性及稳定性方面着笔,希望能通过些许文字的分析和介绍,来窥探http平台搭建所涉及的一些技术细节,给读者以启发。

 

协议的安全性

http协议其所涵盖的信息都是未经加密的明文,包括请求参数,返回值,cookiehead等等,因此,外界通过对通信的监听,轻而易举便可模拟出请求和响应双方的格式,伪造请求与响应,修改和窃取各种信息。相对于tcp协议层面的socket传输方式,针对http协议攻击门槛更低。因此,基于http协议的webSOA架构,在应用的安全性方面,需要更加的重视。

 

1.摘要签名

对于普通的非敏感数据,我们更多的关注其真实性和准确性,因此,如何在通信过程中保证数据不被篡改,便成为首当其冲需要考虑的问题。鉴于使用https性能上的成本以及需要额外申请CA证书,这种情况下,一般采用参数摘要的方式即能够满足需求。每次请求和响应生成对应的sign,以此来保障请求及响应不被第三方篡改。

请求的参数经过排序,将参数名称和值经过一定的策略组织起来,加上一个密钥secret,然后通过摘要算法生成sign。常见的摘要算法包括MD5SHA等等,由于摘要算法的不可逆性,以及请求参数值的多变性,能够在一定程度上保证通信的安全性。

签名的构造

 

服务端接收到请求后,以同样的顺序将参数排序,加上相同的secret,以相同的摘要算法生成签名,然后与请求传过来的sign进行比较,如果参数在中途被篡改,传过来的sign与服务端生成的sign则存在差异,以此来判断请求的合法性。

签名的校验

服务端校验完成后,生成响应,同样的,响应的内容也需要以类似的方式进行签名,客户端收到响应后,根据接收到的sign来验证签名的正确性。

举例来说,某个请求的url可能是这样,www.xxx.com/api.do?userid=12345678&page=1&pagesize=10&signtype=MD5&charset=gbk&method=com.chenkangxian.getname&sign=aef503e0ae7c27b04c2fe1cc95ce1duseridpagepagesize是常规参数,signtype表示加密类型,charset表示编码,method表示接口名称,sign为生成的签名串,为了互联网传输方便,一般对其进行16进制或者base64编码,服务端将接收到的参数拼接成字符串userid=12345678&page=1&pagesize=10&signtype=MD5&charset=gbk&method=com.chenkangxian.getname,采用MD5算法生成sign,与传递过来的sign(当然,需16进制或者base64解码)比较,如果一致,表示参数未被篡改。

 

 

2.公私钥签名

上述方法能较好的解决数据合法性校验问题,但是secret相对固定,如果多客户端调用,容易导致secret泄露。

因此,可以给每个客户端分配一对公私钥,请求时,客户端将参数按与前面类似的方式排好序,拼成一个字符串,md5后,通过私钥加密,生成sign

图3 客户端用私钥生成sign

服务端采用同样的方式将参数编排,拼成字符串,md5,通过客户端公钥解密sign,与其md5生成的值进行比较,便可得出数据是否合法。

 

图4  服务端用公钥校验sign

 

当然,客户端也可以采用相同的方法,使用服务端的公钥,对服务端进行校验,这里就不一一枚举了。

 

3.https

上面的两种方法能较好解决数据合法性问题,但对于一些较为敏感的信息,如隐私数据,用户名密码等等,这些信息如以明文的形式传递,会带来较大风险,服务端secret或者公私钥相对固定,一旦密钥泄露,也会有很大的安全风险,并且,通信过程中,客户端与服务端的身份,特别是服务端的身份难以得到保障,第三方可以通过域名劫持的方式来伪造身份,欺骗客户端向伪造的服务端发送数据,这样一来,损失将不可估量。因此,有必要采用更加严格的加密手段来保障信息的安全。

依托SSL(Secure Socket Layer)协议,https能够确保整个通信过程加密,密钥随机产生,并且能够通过数字证书验证通信双方的身份,以此来保障信息安全。

服务端单向身份认证https通信过程

SSL协议握手的过程是这样的,客户端向服务端发送SSL协议的版本号,支持的加密算法类型,产生的随机数以及其他客户端与服务端通信所需要的信息,服务端收到这些信息后,会将它自己的SSL协议版本,支持的加密算法类型,以及产生的随机数等等内容,加上它的数字证书,一起回复给客户端。

证书以证书链的形式组织,客户端会逐级校验证书的合法性,包括服务器域名是否与证书所声明的域名一致,证书是否过期,证书颁发机构是否是可信赖的等等。这个过程对于用户来说一般是透明的,操作系统会内置一些知名的CA机构的根证书,免去用户的安装步骤,开发者或机构只需要向相关的CA机构以付费的方式申请证书即可。当然,也有个别例外的奇葩,如12306,直接将根证书挂在主页上供用户下载。

校验完证书过后,客户端将产生一个预主密码,并用服务端的公钥加密传送给服务端,服务端会根据预主密码来生成通信密码,与此同时,客户端也通过相同的方式生成通信密码,这样,一次通信握手基本完成。

通过SSL协议能够完成对服务端的认证,加密数据,防止在传输过程中信息的泄露和篡改,能够在相当的程度上保障通信的安全性。

 

4.应用授权

以上的场景其实是在通信双方相对信任的基础下完成的,客户端直接访问服务端完成数据交互。还有一种场景是平台商将数据有限开放给第三方软件厂商(ISV),第三方软件厂商再利用这些数据来给用户提供服务,当然,前提是用户必须对ISV授权。对于平台厂商来说,用户形形色色的需求,很难以一己之力来予以充分满足,因此,将数据以接口的形式下放给众多的第三方开发者,便成了必然的趋势,也正是由此引发了近几年的“开放平台热”。这样,如何保障对用户数据的访问均是经过授权的,且不会对第三方泄露用户的用户名密码,便成了首当其冲的问题。

OAuth协议为用户资源的授权提供了一个安全、开放的标准,与以往的授权方式不同,OAuth不需触及到用户账户信息(用户名密码),即可完成第三方对用户信息访问的授权。

开放应用平台授权

OAuth协议的出现,使得用户在不泄露自己用户名密码的情况下,能够完成对第三方应用的授权,第三方应用得到用户授权后,便可以在一定时间内访问到用户授权的数据。

7 Oauth协议的授权过程

 

一次OAuth协议的授权过程如上图所示,用户先对ISV发起请求,ISV向平台商请求request token,带上其申请的app id,平台返回request token,其后ISV应用将用户引导到平台的授权页面,带上自己的app idrequest token以及回调地址,用户在平台的页面上完成授权(这样便不会将用户名密码泄露给第三方),然后平台通过ISV提供的回调链接,返回给ISV应用access tokenISV应用通过access token取到用户授权的数据,进行加工后返回给用户,授权完成。

为了确保通信安全,一般会让ISV使用其私钥对参数进行签名,平台使用ISV的公钥进行签名验证,来校验ISV的资质,具体过程前面详细介绍过,此处不再赘述。

OAuth协议得到了国内外互联网公司的广泛认可,包括FacebookGoogleWindow Live,以及国内的腾讯、新浪、淘宝、人人等,都对其提供了良好的支持。不同的厂商有不同的OAuth版本,但不论是OAuth1还是OAuth2,其核心思想都是将资源做权限分级和隔离,ISV引导用户在平台端登陆,完成授权,获得授权后ISV可以在一定时间段内访问用户的私有数据,用户完全把控这一过程,且授权可取消。这样,第三方ISV能够利用平台商所拥有的一些数据,来服务用户,为用户创造价值,形成了一个生态系统的闭环。

OAuth授权其实是一个相对较复杂的体系,涵盖系统的方方面面,包括之前所说的通信加解密,以及权限划分,token生成和校验,公私钥的管理,还有后面将要提到的分布式session机制等等。相对于前几年来说,由于开源社区的发展,为其的实现降低了不少门槛,目前已有很多开源的解决方案,详情请参照OAuth网站(http://oauth.net)

 

session的安全性

对于互联网应用来说,为了应对高并发访问的压力,支撑其业务的往往不止是单台服务器,而是一个分布式集群,http请求在不同的服务器间跳转,这样集群间session的同步便成了不得不考虑的问题。

对于一般web应用来说,采用cookie能解决一部分问题,但随着应用规模的不断扩大,cookie会不断的膨胀,而浏览器对于每个域名下的cookie的个数以及每个cookie的长度会有所限制,不能满足持续性增长的需要,并且,客户端的cookie数据会存在一定的安全性隐患。对于服务端调用来说,请求不经过浏览器,cookie显然无法满足需求,随着移动互联网的发展,基于httpSOA架构还将兼容无线客户端的请求,因此,基于cookiesession同步方案已无法满足需求。

基于cache的分布式session结构

如上图,基于cache的分布式的session同步机制,能较好的解决上述问题。客户端通过login登陆,如果客户端为浏览器,则通过cookie回写的方式,设置sessionid,如果是在移动端或者服务端调用,则直接返回sessionid,这样,不管用户如何跳转,不同的客户端和应用都可以通过sessionidcache集群中取到session,避免了session丢失。

而使用一致性hash算法,能够确保当某台cache server宕机后,不至于整个的key都重新hash一遍,导致所有的用户都需要重新登录,这样不仅提升了用户体验,也降低了对于login的压力,不会有大量的用户像雪崩一样同时发来大量的登录请求(这对于像淘宝双1112这样大流量的活动来说,十分重要)。使用cache来存储session会话,即表示会话是可以丢失的,对于系统设计者来说,对这一点须有清楚的认识。

分布式session也会跟普通单机session一样,存在session失效以及cookie防盗用等等问题。

为提高cache的利用率以及提高session的安全性,须针对cache设置一定时长的失效时间,避免在用户在离开位置后session被其他人盗用,但是,对于用户连续性的操作,又必须对session的到期时间进行不断更新,否则,可能会影响到用户的体验。

对于sessionid来说,最好是将其设置为httponly,避免跨站脚本对cookie进行盗用,当然,采用分布式session后,任何人都已经很难从cookie本身提取到有价值的攻击信息,但是,如果通过窃取sessionid来伪造用户登陆,则不得不防,尤其是交易相关的业务,可能会造成相当大的危害,因此,需将session的状态与客户端的ip地址或者mac地址挂钩。如果用户从ip1登陆,通过ip2来访问用户信息,即便ip2访问的时候带上了sessionid,也需要重新进行登陆,这样的话,则相当程度避免了会话劫持的发生。

 

 

平台的稳定性

对于生产环境的应用集群来说,故障是很难完全避免的,建立完善的监控预警机制,能够提高遇到问题时的响应速度,帮助快速发现问题,及时通知相关技术人员对故障进行修复,有效的避免或者降低损失。与此同时,也必须做好流量控制,防止突发的大流量将服务器压垮。

 

1.集群监控

生产环境的情况往往复杂多变,用户的行为不可预测,有效的监控措施不仅能够提高遇到问题时的响应速度,也为应用的扩容,性能的优化提供了参考依据,对我们及时了解应用的水位,评估和设置警戒线提供了十分重要的帮助。

常规的监控可以包括如下方面,机器的loadcpu使用率,内存使用率,网络trafficpv以及uv信息,IO繁忙程度,磁盘使用率,异常catch等等,如果是java应用,应该包括堆栈的使用情况,fullgc的频率等等,如果是mysql DB,需要包括select/psupdate/psthread running等等,这些指标信息能够基本反映机器运行的健康状态。一旦某个指标出现异常,比如受攻击导致流量激增,可以发短信或者邮件通知相关应用负责人,进行及时的处理。

对于采用http协议的应用来说,能做的不仅仅只有这些,还可以采取包括接口数据校验,部分线上回归测试,页面状态检测等等措施,更加全面的对应用进行健康检查和监控。

举例来说,对于异步返回jsonjsonpxml格式数据的接口来说,可以事先造好一部分固定数据,覆盖接口代码的各个分支路径,然后通过shell脚本定时执行(crontab部署定时任务)的方式,验证返回的数据是否完整是否正确,以此完成接口的扫描与检查。

 

Shell代码  收藏代码
  1. $CURL_BIN -s -m 100  "${HOSTNAME}${URL}" > $TMP_FILE  
  2. if [ "$CHECK_TXT" != "" ]; then  
  3.     check_result=`fgrep $CHECK_TXT $TMP_FILE`  
  4.     if [[ "$check_result" = "" ]]; then  
  5.        CHECK_STATUS="1"  
  6.        echo -e "check failure!\t${URL}\n"  
  7.     fi  
  8. fi  

 

code1 接口检查shell片段

脚本通过curl来请求相关接口url,将返回值与check_txt(预定义文本)通过fgrep比对,如果与预计的不符,则输出check failure,程序检测到该输出,则发送短信报警。

对于页面来说,返回的数据量大,整体校验相对来说代价较大,可以针对一些核心流程,比如接口的调用,后端数据的返回,定义一些状态码,塞到httpheader请求头中返回,这样,通过监控header中对应的状态值,来完成页面的监控。

 

Shell代码  收藏代码
  1. $CURL_BIN -s -I -m 100  "${HOSTNAME}${URL}" > $TMP_FILE  
  2. status=` awk -F ":" '{if($1 == "Server_Status"){print $2}}' $TMP_FILE `  
  3. status=${status//}  
  4. if [ "$status" = "ok" ]; then  
  5. CHECK_STATUS="0"  
  6. else  
  7. CHECK_STATUS="1"  
  8. echo  -e  "check failure!\t$URL\n"  
  9. fi  

 

code2  一段页面监控的shell片段

脚本通过curl来访问相关页面,通过awk过滤出header中的Server_Status(该值在应用端事先约定好),判断其是否为ok状态,如果ok,则忽略,否则,输出check failure,程序检测到该状态,则发送报警短信。

 

 

2.并发与流量控制

任何应用都有一个设计指标和能承载的峰值,当它的压力超过了它设计的峰值以后,就好比一座为行人设计的独木桥,即使它再坚固,也无法让一辆坦克行驶通过,在这个时候,为了让机器能够正常运行,不至于完全瘫痪,需要对应用进行流量控制。

控制的策略有多种,可以直接丢弃掉那部分超出峰值的用户请求,这样虽然比较粗暴,但也是最简单最有效的方法,还有一种便是削峰填谷,将一部分暂时来不及处理的请求放入等待队列中,待资源空闲时再逐步消化,具体使用哪种策略,与应用的场景相关。

当然,要进行流控,首先得有一个进行流控阀值,这可不是拍拍脑袋或者仅凭经验就能够得出来的,不同的应用,不同种类的接口,不同的机器配置,其所面临的情况也不尽相同,阀值必定是有差异的,必须经过几轮的压力测试下来,才能够得到一个比较靠谱的值。

流控可以从多个维度来进行,比如针对qps(每秒查询数),并发线程数,黑白名单,服务加权分级等等,最典型最直观的,便是通过对qps或者是并发线程数的控制,来达到限流的目的。

从具体实施的角度来说,可以在应用的负载均衡端(nginx)完成,这一层可以进行整体的比较粗粒度的控制,比如客户端的并发请求数,请求的频率等等,这样可以过滤掉大部分攻击请求,提高ddos的组织难度,当然,更加复杂的策略,如验证码防刷,黑名单,ip封锁等等,可以通过编写nginx模块来进行定制。

Nginx0.7版开始提供2个限制用户连接的模块HttpLimitZone ModuleHttpLimitReq Module,可以用来限制用户请求的频率和并发连接数:

Nginx代码  收藏代码
  1. limit_zone  zone_session_state  $binary_remote_addr  10m;  
  2. limit_req_zone  $binary_remote_addr  zone=req_session_state:10m  rate=1r/s;  
  3. location /  
  4. {  
  5.       limit_conn  zone_session_state 1;  
  6.       limit_req  zone=req_session_state  burst=5 nodelay;  
  7.       …   …  
  8. }  

 

code3  nginx配置限流

负载均衡端作为应用总的流量入口,采取的限流措施可以挡掉大部分的恶意流量,但缺乏灵活性,难以响应后端的变化,并且受调度策略的影响,并不能保证落到每一台服务器的流量都是均衡的,因此,一般的策略是将入口阀值适当调高,然后结合应用端协同来进行流控。

应用端流控的好处便是能够更细粒度的划分流控的单位(能精确到接口层面),更加方便的调节流控阀值,动态的修改服务权重、调用的黑白名单,以及进行服务分级,优先保障核心流程的稳定,这在应对大流量高并发的压力 (如淘宝双11,双12)时,显得尤为重要。

关于应用端流控的实施,涉及众多细节,限于篇幅,笔者将在个人博客做详细介绍,此处便不再赘述。

 

 

小结

本文从协议的安全性,session的安全性以及平台的稳定性三个方面,介绍了http平台搭建过程中所面临的一些问题以及解决办法。http协议因其明文传输的特性,使得在系统设计阶段,不得不对安全性作充分考量。而对于生产环的境应用来说,完善的监控预警措施,能确保在第一时间发现问题,及时采取恰当的措施,避免损失;合适的流控机制,能保障在流量突增的情况下,机器能顶住压力,不至于宕机。

 

分享到:
评论

相关推荐

    大型分布式网站架构设计与实践.带目录书签.完整版.rar

    曾在程序员上发表过《漫谈基于http协议的SOA架构》《浅析HTTP平台的安全稳定性架构》两篇文章,对基于HTTP协议的SOA架构有深入研究,在排查解决线上问题和故障方面有丰富的实践经验,擅于利用数据分析解决实际问题,...

    电力信息系统安全.doc

    因此在加强信息系统自身的稳定性同时, 也要防范利用网络系统漏洞进行攻击、通过电子邮件进行攻击解密攻击、后门软件攻击 、拒绝服务攻击等网络上带来诸多安全问题。 如何应对好网络与信息安全事件。要把信息安全...

    2021 Gdevops全球敏捷运维峰会(广州站)PPT汇总(含15个PDF)

    美图:低成本全链路监控实战与SRE稳定性运营 网易游戏面向终态的应用交付管理实践 三、数据库专场 TDengine的创新与最佳应用场景 如何打造稳健的数据库管理平台 超大规模数仓集群在大型商业银行的落地实践 基于...

    Gdevops广州 2021年全球敏捷运维峰会PPT合集(17份).zip

    低成本全链路监控实战与SRE稳定性运营 面向终态的应用交付管理实践 企业一站式DevOps平台建设实践 维稳618和双11:数据库海量运维的生态体系建设与实践 银行复杂架构下的数据库敏捷运维 游戏混沌工程实践 ABC场景...

    Gdevops广州站 2021年全球敏捷运维峰会PPT合集(17份).zip

    低成本全链路监控实战与SRE稳定性运营 面向终态的应用交付管理实践 企业一站式DevOps平台建设实践 维稳618和双11:数据库海量运维的生态体系建设与实践 银行复杂架构下的数据库敏捷运维 游戏混沌工程实践 ABC场景...

    2021 Gdevops全球敏捷运维峰会(广州站)PPT汇总(15份).zip

    美图:低成本全链路监控实战与SRE稳定性运营 网易游戏面向终态的应用交付管理实践 三、数据库专场 TDengine的创新与最佳应用场景 如何打造稳健的数据库管理平台 超大规模数仓集群在大型商业银行的落地实践 基于...

    2021 Gdevops全球敏捷运维峰会(广州站)4个专题共17份.zip

    低成本全链路监控实战与SRE稳定性运营.pdf 维稳618和双11:京东科技数据库海量运维的生态体系建设与实践.pdf 网易游戏面向终态的应用交付管理实践.pdf 腾讯游戏混沌工程实践.pdf 银行复杂架构下的数据库敏捷运维.pdf...

    总监课第五期第五节质量保障大规模原生云质量保障浅析.pdf

    阿里云专有云与阿里云公共云同根同源,...本期专有云技术专家团齐上阵,从基础架构、产品设计方向、技术研发以及工程效率等方面为您全维度揭晓在不断追求稳定性的过程中,专有云技术和产品的实践与探索。 主要章节:

    “互联网+”时代服务器的评估.doc

    技术成本是指采购成本、升级运维成本和占比耗能成本,而业务成本是指服务器性 能的稳定性和未来的升级能力、内存容量、远程集中管理能力和能耗控制能力,以及IT 对新应用开发部署、应用扩展和满足高性能、大数据应用...

    代码之美(中文完整版).pdf

    20.6 稳定性 20.7 结束语 第21章 ERP5:最大可适性的设计 21.1 ERP的总体目标 21.2 ERP5 21.3 Zope基础平台 21.4 ERP5 Project中的概念 21.5 编码实现ERP5 Project 21.6 结束语 第22章 一匙污水 第23章 MapReduce...

    asp.net知识库

    Asp.net 利用OleDb的GetOLEDBSchemaTable方法得到数据库架构信息 用于 Visual Studio .Net 的 IBM DB2 开发外接程序 第2章 并发操作的一致性问题 (2) Using sqlite with .NET Visual Studio 2005 中的新 DataSet ...

Global site tag (gtag.js) - Google Analytics