现如今越来越多的企业使用"智能客服系统"服务于自己企业的客户,如何既能享受智能客服带来的服务能力提升,还能兼顾企业的信息安全呢? 云问作为国内智能客服行业领先产品服务提供商,结合多年客户落地案例,形成一整套智能客服安全架构解决方案,与大家共同学习进步。
服务部署与通信架构图
企业智能客服有一个特征,最终服务的客户一般在互联网中发起咨询,归属公网。最终服务的机器人与坐席、知识库都在内网,知识维护人员在内网,坐席服务人员也在内网,这样的网络隔离才能做到网络安全、信息安全。故将智能客服的网络层次分为:公网、DMZ区域、LAN内网区域,一层一层隔离,每一层都有严格的网络、IP、端口开放策略,这样才能做到信息安全。
大家可能看到一个内外网不一样的节点,那就是WAF(Web Application Firewall,Web应用防护系统)。在考虑到最终使用智能客服的访客都是在互联网当中,而互联网是一个公开的网络,会收到很多恶意攻击,在应用服务器的前面加一层WAF保护,可以很好的阻挡一系列不安全的攻击。
如何实现高可用与热更新
从上图的部署通信架构图中可以看出,每个服务都是两个实例,并且两个实例都是双活的,有Nginx进行负载,智能客服这种带会话属性的产品特性,适合采用Session保持的负载策略。仅仅只有Nginx一层负载做高可用是不够的的,万一Nginx挂了怎么办呢,有条件的客户还可以使用Ctrix做虚拟IP负载到两台双活的Nginx当中,这种逐层做负载与高可用的方法,可以大大增强产品服务的可用性。这里以一个服务两个实例做的高可用,各个企业可以根据实际流量情况,采用3机、4机做负载 都是完全可以的。Nginx多机负载的各种测试可以参考博文《【Nginx】 配置负载–Nginx配置详解与负载方案详解》
下面谈谈热更新,经常听朋友圈里同事说,今晚更新升级啊,要通宵。额,这不已经是多机负载了吗?怎么还有到晚上停机停服务更新呢? 上图中的部署架构,是完全可以做到不停服务随时做热更新的,大致流程方法为:动态调整Nginx负载配置,剥离一台机器,单独对这台机器做更新升级,然后用同样的方法再剥离另外一台做更新,最后在Nginx中,将两台机器同时上线服务,最终做到业务不停机更新。注意这里采用的修改Nginx的配置的方式,而不是直接停止其中一台机器服务的方式,这种方式可以更友善的把原本机器中的服务请求响应完成,而不是简单粗暴的停止服务。
采用如上的热更新,对产品研发设计有一定的要求,需要产品的研发模式必须支持向前兼容的模式,不管是接口还是数据库物理模型,都要向前兼容,不然无法做到不停服务热更新。
如何实现内外网共同安全服务(HTTPS)
企业智能客服系统有一个特色,就是最终消费知识的访客一般通过微信、App、官网等渠道在互联网中进行消费,而消费的知识一般都是企业知识管理员在内网进行维护,坐席服务人员(在访客转人工之后)同样也都是在内网进行服务的。
这个情况下,安全性意识不太高的企业,直接使用一个域名都在公网进行服务与维护,此时智能客服系统的全部功能与接口都是暴露在公网的,其实是一件非常危险的事情。而有一些企业要求的安全规范很高,仅暴露必须在公网服务的接口,其他都放在内网,为了达到这个述求,就需要两个域名,一个域名用于公网访客开启Https访问,另外一个域名用于内网知识管理与坐席人员提供服务。
内外网两个域名,分别颁发两个证书,外网证书由公共组织签发,由dmz区域的两台nginx使用。为了安全,不管在内网还是外网,都需要使用Https协议。
内网域名证书由企业自己签发,应用于 内网所有服务器(如上图中的3个nginx、8个tomcat)。如证书目录放在:/airobot/server/nginx/conf/ssl/中,csr证书信息文件有:crt证书、 key私钥。
内网tomcat使用证书的配置如下。 如在目录:/airobot/server/tomcat_chatbot/conf/server.xml当中,配置如下内容让Https生效。
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="9443" maxThreads="3000" SSLEnabled="true"
scheme="https" secure="true" connectionTimeout="60000"
xpoweredBy="false" allowTrace="false" enableLookups="false" maxHttpHeaderSize="8192"
keystoreFile="/airobot/conf/ssl/server.jks" keystorePass="password"
clientAuth="false" sslProtocol="TLS" />
<Context path="/chatbot" docBase="/airobot/webapps/chatbot" privileged="true" debug="0" reloadable="false"/>
在目录/airobot/conf/ssl/中,存放企业自己颁发的windows格式的原始证书文件,server.jks是由原始证书转换而来。
如内网的Nginx配置文件在目录在/airobot/server/nginx/conf/airobot.conf中,需要增加如下配置
listen 443 ssl http2;
server_name airobot.ddd.cn;
ssl_certificate /airobot/server/nginx/conf/ssl/airobot.ddd.cn.crt;
ssl_certificate_key /airobot/server/nginx/conf/ssl/airobot.ddd.cn.key;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1.2;
ssl_ciphers "some words,some words, some words";
坐席人员使用内网浏览器管理知识与提供服务,可使用域控(AD)和证书服务器(CA)绑定,此域账户中的浏览器即可安全使用。
既然要在内往通过不同的域名外共同服务,就要规避一个坑:静态资源(文档、图片等)只能使用相对路径,因为只有使用相对路径,才可以确保不管内网访问访问还是外网访问的时候,都动态拼接当前访问的域名。 在这里可能会有同学会问,静态资源使用OSS资源服务啊,搞那么服务干什么?可实际情况是,企业服务的静态资源都是带有机密和权限,都是经过知识管理者管理和编辑的,是不能随便暴露在公网其他服务的,并且很多企业安全级别规定,内网工作的机器,是不能访问外网的。
中间件加固 让服务更安全
为了使智能客服服务架构更安全,系统架构使用的中间件加固也是一件非常重要的事情。中间件(如Nginx、Tomcat)需要每隔一段时间升级到最新版本,对每一个中间件都需要配置安全加固项。如下举例两个最常见中间件Nginx与Tomcat的加固项内容截图:
漏洞扫描发觉潜在威胁中间件加固 让服务更安全
上面说到了中间件的安全加固,下面来看看同样重要的代码漏洞检查。常见的漏洞扫描的办法较多,有公司专门提供漏扫检查服务的(如绿盟等)进行一次性的代码安全整改,规模较大的企业会自己购买漏洞软件,提供长期的,每次升级都要进行的漏洞扫描,如Contrast Security。这样就可以通过应用程序的运行状态,时刻监控“程序代码漏洞”与“Library包漏洞”。下面分别截图看看程序代码漏洞”与“Library包漏洞”的样例:
常见的漏洞与解释如下
- Path Traversal from Request Body on “URL地址” page:存在从请求中路径遍历所有可能的文件(如果资源文件名是无规则重编码过的,可以规避此风险)
- SQL Injection from Request Body on “URL地址” page:SQL注入风险,这种情况都是要解决的。
- Cross-Site Scripting from Request Body on “URL地址” page:XSS漏洞攻击,都是要解决的
- SHA-1’ hash algorithm used at ByteString.kt:“不安全加密”风险,SHA-1和MD5已经被破解,需要使用SHA-256进行加密,修改对应代码中加密算法。
- ‘MD5’ hash algorithm used at TokenBasedRememberMeServices.java:“不安全加密”风险,SHA-1和MD5已经被破解,需要使用SHA-256进行加密,修改对应代码中加密算法。
- 等等等
而Library的漏洞可能就稍微麻烦一些了,升级Library比较简单,但是系统的框架与业务代码应用需要同步修改,这种的风险和工作量就比较大了,需要特别小心。
常见问题与解决方案
在最后一章节,我们来看看,上面安全的智能客服架构,安全是很好的,但安全也是有代价和坑的,我们云问在智能客服领域有多年实战经验耕耘,我们把这些代码和坑贡献出来,以减少同行业者在IT建设过程中的代价:
-
在如上安全架构中,公网接入中开通waf之后,应用程序会无规律的出现系统有时登入成功,有时登入失败的情况。这个问题的本质原因是开通waf后,waf会默认开启分配动态IP,导致会话保持不住,产生需要重新登入的问题。需要关闭waf的动态IP分配策略,把源ip透传过来,开启会话保持。nginx的分析截图日志如下:
-
在前面的中间件加固项当中,有一些关于限流的加固项,如果nginx之前的负载(如Ctrix)做不到透传终端访客的IP地址,是没有办法做限流的,开启了就会导致无规律的间断性接口不可用。限流的方法与说明如下:
connection是连接,即常说的tcp连接,通过三次握手而建立的一个完整状态机。建立一个连接,必须得要三次握手。
request是指请求,即http请求,(注意,tcp连接是有状态的,而构建在tcp之上的http却是无状态的协议)。
通过打开一个网页,然后通过wareshark可以看到,一个连接建立后(即三次握手后),在这个连接断开之前(即四次挥手之前),会有很多的http request,这就是他们的区别:即一个连接的生命周期中,会存在一个或者多个请求,这是为了加快效率,避免每次请求都要三次握手建立连接,现在的HTTP/1.1协议都支持这种特性,叫做keepalive。
limit_conn_zone $binary_remote_addr zone=limitperip:10m
第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
第二个参数:zone=limitperip:10m表示生成一个大小为10M,名字为limitperip的内存区域,用来存储访问的频次信息。
代表:启一个名为只limitperip的定义,定义同一个客户端ip地址的连接的数量。
limit_conn limitperip 10;
代表:使用上面的zone=limitperip这个名字的定义,并且限定 同一个客户端ip地址的最大连接的数量未10.
limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=5r/s;
第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
第二个参数:zone=mylimit:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息。
第三个参数:rate=5r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒5次,还可以有比如30r/m的。
limit_req zone=ratelimit burst=10 nodelay;
第一个参数:zone=ratelimit 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应。
第二个参数:burst=10,重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为10的缓冲区当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
第三个参数:nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队。
-
开通waf之后,接口有时会出现 403 Forbidden错误。本质原因是waf的默认规则中有一条,如果http请求参数中包含html标签,waf会认为存在XSS攻击,不让请求通过。 需要将html标签参数内容,在前端进行转义,在后端进行解密进行。403 Forbidden接入如下:
-
在《如何实现内外网共同安全服务(HTTPS)》一节中,有说过每个服务的Tomcat也都是开启Https的,并且只能开启Https协议,这个时候需要特别注意一个问题,那就是Tomcat与Tomcat之间有Http调用的时候,需要在HttpClient工具中,开启免除https秘钥校验,因为tomcat服务在内网已经有了第一层安全保障,tomcat服务于服务之间都是存在白名单的,更加直接的控制访问策略。