规范目的

随着开放平台的发展,越来越多的服务商通过开放平台接入到贝尔康的生态圈,为了更好的促进贝尔康生态的良性发展,保障开发者在合作过程中的数据安全特制定本规范。目的是为了帮助第三方应用,规范其在开发过程中可能存在的安全隐患,为提供第三方应用提供安全性建议,保证服务接入的安全性。

使用范围

所有通过开放平台接入的第三方应用。

一、通用准则

1.1 设立安全角色

跟据组织的规模设立安全角色,至少保证组织中有1名人员作为安全角色。

1.2 补丁和漏洞管理

必须及时安装与安全性相关补丁,建议:

关键和重要的更新及补丁需要在十天内部署

中等优先级的更新及补丁需要在三十天内部署

低等优先级的更新及补丁可以在九十天内部署

1.3 避免弱口令

避免使用弱口令,建议口令复杂度同时满足:

长度≥8位

包含数字、字母、特殊符号

避免键盘连续字符

避免口令包含用户名

1.4 通信加密

通信过程中使用SSL层加密通信内容,防止通信内容被窃听、中间人攻击。

1.5 防通信伪造

对于HTTP应用,通过参数签名验签,防止通信伪造。

二、规范细则

说明: 细则主要以Java开发语言为主,但是以下描述的安全并不限定开发语言。当您处理的不是Java语言时,请参考相同的思路寻找对应的防御建议。

2.1 主机安全

主机应该及时打安全补丁,避免攻击者通过相关利用程序攻击。

如果使用云厂商服务,请关注其是否提供补丁服务。

2.2 通信安全

应用通信使用HTTPS协议,避免通信被劫持、窃听、中间人攻击。

SSLTLS版本应当禁用存在诸多安全风险的版本,包括SSLv1、SSLv2、SSLv3、TLSv1.0;如果可行,禁用TLSv1.1。

备注: 可以通过如下地址检查您的网站支持SSLTLS版本https://tomcat.apache.org/lists.html#tomcat-announce

2.3 中间件安全
2.3.1 Tomcat
2.3.1.1 防止管理页面弱口令

Tomcat默认携带Manager应用,用于管理部署、卸载等,如果使用管理页面,需要设置强密码,密码复杂度可参考 1.3 避免弱口令。

通常您不会使用该管理页面,如果您确认不会使用,请删除Manager应用(删除webappsmanager目录)

代码块

Plain Text
|--bin
|--conf
|--webapps
|  |--manager
|  |--ROOT
|  |--examples

2.3.1.2 关闭指令增强
如果需要通过本地Tomcat服务的网络端口来关闭Tomcat,关闭指令必须设置为强复杂度并且难以猜测。

编辑文件CATALINA_HOME/conf/server.xml,设置关闭指令:

代码块

<Server port="8005" shutdown="这里设置成复杂的指令,防止被猜测">

通常该功能不是必需的,如果您确认不需要使用此功能,请禁用之:

代码块

<Server port="-1" shutdown="SHUTDOWN">

2.3.1.3 禁用不必要的HTTP方法
Tomcat服务器提供默认http方法包括GET、HEAD、POST、PUT、DELETE、OPTIONS。

在配置前,需要了解产品是否会使用到这些HTTP方法,如果用不到,则必须禁用。

在tomcat目录下的web.xml中配置:

代码块

<security-constraint> 
  <web-resource-collection>               
    <url-pattern>/*</url-pattern>               
    <http-method>PUT</http-method>               
    <http-method>DELETE</http-method>               
    <http-method>HEAD</http-method>               
    <http-method>OPTIONS</http-method>               
    <http-method>TRACE</http-method>           
  </web-resource-collection>           
  <auth-constraint>           
  </auth-constraint>   
</security-constraint>

在Tomcat的web.xml 文件中配置org.apache.catalina.servlets.DefaultServlet的初始化参数:

代码块

<init-param>       
  <param-name>readonly</param-name>       
  <param-value>false</param-value>   
</init-param>
2.3.1.4 禁用WebDAV

WebDAV(Web-based Distributed Authoring and Versioning)是基于 HTTP 1.1 的一个通信协议。它为 HTTP 1.1 添加了一些扩展,使得应用程序可以直接将文件写到 Web Server 上。WebDAV存在一定的安全问题。

Tomcat支持WebDAV的,但是默认不启用。 请确保以下配置在web.xml中不存在或者为注释状态:

代码块

<servlet>
    <servlet-name>webdav</servlet-name>
    <servlet-class>org.apache.catalina.servlets.WebdavServlet</servlet-class>
</servlet>
2.3.1.5 禁用列目录

允许列目录会造成信息泄露;另一方面,由于生成具有数千个文件目录的列表会占用大量的CPU资源,将会导致DoS攻击。

生产环境必须禁用列目录,设置DefaultServlet设置list为false:

代码块

<servlet>
   <servlet-name>default</servlet-name>
   <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
   <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
   </init-param>
   <init-param>
       <param-name>listings</param-name>
       <param-value>false</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
2.3.1.6 删除示例程序

Tomcat默认携带示例程序,提供样例,通常在生产环境中,您不会使用该示例程序。

删除示例程(删除webappsexamples目录)

代码块

Plain Text
|--bin
|--conf
|--webapps
|  |--manager
|  |--ROOT
|  |--examples
2.3.2 JBoss
2.3.2.1 jmx-console增加密码限制
如果您不需要使用jmx-console,优先删除其对应的war($JBOSS_HOME/[server]/all/deploy 和 $JBOSS_HOME/[server]/default/deploy下的 jmx-console.war )。

如果您确实使用,请启用认证,且使用强复杂度口令。

2.3.2.2 防止反序列化造成远程命令执行

JBoss中的http-invoker.sar暴露的/invoker/readonly 接口可以接受序列化数据,接口执行反序列化时未恰当检查。通过精心构造恶意的序列化数据,可以远程执行命令。通常应用不需要http-invoker.sar 组件,如果您确认不需要,可删除此组件。

2.3.3 Weblogic
2.3.3.1 防止反序列化造成远程命令执行

近年来,Weblogic陆续被披露存在高危漏洞,其中最常见的是反序列化,通过精心构造恶意的序列化数据,可以远程执行命令,入侵系统。如果您的应用使用了Weblogic,请密切关注其官方的安全公告,并及时更新安全补丁。

2.3.4 Mongodb
2.3.4.1 防止Mongodb未授权访问

Mongodb默认监听27017端口,未启用认证,攻击者如果网络可达的话,可能会访问您的Mongodb,查询、删除、修改您的缓存数据。

强烈不建议Mongodb服务发布到互联网上

绑定监听IP

代码块

Plain Text
// 当在启动mongodb的时候,使用-bind_ip指定监听IP,数据库实例将只监听192.168.0.1的请求
-bind_ip 192.168.0.1
启动基于角色的登录认证
2.3.5 Redis
2.3.5.1 防止Redis未授权访问

Redis默认监听6379端口,未启用认证,攻击者如果网络可达的话,可能会访问您的Redis,查询、删除、修改您的缓存数据。

强烈不建议Redis服务发布到互联网上

配置Redis仅监听本地地址

代码块

Plain Text
# 修改redis.conf配置文件
bind 127.0.0.1 192.168.13.12 #如只监听来自127.0.0.1 192.168.13.12的请求
配置访问密码

代码块
Plain Text

修改redis.conf配置文件

requirepass @4KI&1*)Ljq19494jd
隐藏重要命令

代码块

Plain Text
// 将 config flushdb flushall 设置为空,即禁用该命令;
// 也可重命名为为一些复杂的、难以猜测的名字
rename-command CONFIG ""
rename-command flushall ""
rename-command flushdb ""
rename-command shutdown shotdown_test
2.3.6 Elasticsearch
2.3.6.1 防止Elasticsearch未授权访问

Elasticsearch 默认端口是 9200,绑定的是本机 127.0.0.1 ,默认参数是安全的。但是如果您修改参数,将Elasticsearch 暴露在互联网,将会带来巨大的安全隐患。如果您确定您需要将Elasticsearch 暴露在互联网,请启用认证:

https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-network.html#common-network-settings

2.3.7 Jekins
2.3.7.1 对管理控制台启用访问控制

通常,管理人员不需要直接在互联网上进行管理,仅需要根据业务自身需求,对管理控制台访问源IP、端口进行限制,防止被攻击者访问管理控制台。关于Jekins的更多加固,请参考:

https://jenkins.io/doc/book/system-administration/security/?spm=a2c4g.11186623.2.19.797a4f6aWwVg1N

2.4 服务安全

2.4.1 防止SSH弱口令

检查您的SSH口令,务必使用强密码,密码复杂度可参考 1.3 避免弱口令,同时定期修改密码。

2.4.2 防止MySQL弱口令

检查您的MySQL口令,务必使用强密码,密码复杂度可参考 1.3 避免弱口令。

2.4.3 防止SQL Server弱口令

检查您的SQL Server口令,务必使用强密码,密码复杂度可参考 1.3 避免弱口令。

2.4.4 防止FTP弱口令

检查您的FTP口令,务必使用强密码,密码复杂度可参考 1.3 避免弱口令。

2.4.5 禁用FTP匿名登录

如果您使用FTP服务,请根据您所使用的操作系统,找到对应设置,禁用FTP匿名登录。

2.5 应用安全

2.5.1 越权防御

您需要确保受限资源仅允许被资源所有者(或所有者授权的主体)访问。

2.5.1.1 防止水平越权

您需要杜绝诸如“用户张三查看李四的订单“、”商户王老板修改商户赵老板的用户信息“。

通常需要配合认证信息来完成检查,比如用户张三登录之后查看订单:

代码块

//1. 在控制层中检查
// 根据订单Id查询订单信息
OrderVo order = OrderService.selectByPrimaryId(id);
// 检查订单所属人与当前登录用户一致
assert(order.getUid() == request.getAttribute("user-context").getUid());
//2. 在DAO中限制
// 根据订单Id、登录用户id查询订单信息
Integer uid = request.getAttribute("user-context").getUid();
OrderVo order = OrderService.selectByPrimaryIdAndUid(id, uid);
2.5.1.2 防止垂直越权

您需要杜绝诸如“营业员查看财务报表“(假定“营业员”不具备“财务”、“经理”、”老板“才具备的权限)通常需要设计角色,不同角色具备相应的权限,然后给不同账户分配相应角色。您需要在接口层面进行限制角色,并且确保不会遗漏接口。如通过注解在接口层检查角色权限:

代码块

@ResponseBody
@Auth(roles=["finance", "manager", "boss"])
@RequestMapping(value = "/financeReport", method = RequestMethod.POST)
public ResponseResult financeReport (@RequestBody FinanceSearchDto financeSearchDto) {
  // 业务代码
}
2.5.2 防止SQL注入

SQL注入可能会造成数据泄露、数据被篡改、服务器被入侵等一系列严重后果。造成SQL注入主要有两个原因:

SQL接收未经净化的参数

参数使用拼接方式

建议使用参数化绑定避免拼接,如JDBC:

代码块

// 使用拼接接受客户端参数,存在SQL注入
JdbcConnection conn = new JdbcConnection();
String sql = "SELECT * FROM `example` WHERE `param`='" + request.getParameter("param") + "'";
conn.execqueryResultSet(sql);
​
//使用参数绑定,避免SQL注入
String sql = "SELECT * FROM `example` WHERE `param`=?";
PreparedStatement ps = (java.sql.PreparedStatement) conn.prepareStatement(sql);
ps.setObject(1, request.getParameter("param"));
ResultSet rs = ps.executeQuery();
mybatis:

代码块

<!--使用拼接接受客户端参数,存在SQL注入-->
<select id="selectByName" resultMap="xxx">
  SELECT `xx`, `yy` 
  FROM `example`
  WHERE `param`=${param}
</select><!--使用参数绑定,避免SQL注入-->
<select id="selectByName" resultMap="xxx">
  SELECT `xx`, `yy` 
  FROM `example`
  WHERE `param`=#{param}
</select>

备注:针对不同语言,不同框架,更详尽的防御建议参考:

https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.md

2.5.3 避免跨站脚本攻击

跨站脚本攻击(Cross-Site Scripting,XSS),指恶意脚本被注入到可信的网站中,恶意脚本在浏览器中渲染执行。攻击者可利用XSS漏洞获取用户Cookie,传播蠕虫,篡改页面或进行钓鱼等。防御XSS通常是通过转义,针对PHP:

代码块

/*未处理参数输出,存在XSS*/
<?php
    $value=$_GET['param'];
    echo $vaule;
?>
​
/*HTML转义,防止XSS*/
<?php
    $value=$_GET['param'];
    echo htmlspecialchars($vaule);
?>

备注:针对不同语言,不同框架,更详尽的防御建议参考:

https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md

2.5.4 避免服务端请求伪造

服务端请求伪造(Server-Side Request Forgery, SSRF)应用程序可能存在这样的场景:获取客户端传递的URL参数,然后在服务端发起网络请求下载URL指向的资源。SSRF的危害是跨越了网络边界,从边界外访问边界内的资源。您应当避免没有对URL参数检查就在服务器发起请求,建议做如下检查:

限制URL参数中的协议(大部分情况应用仅使用HTTP(s) 就够了)

检查URL中的host,如果可行,使用白名单列表检查host是否匹配;如果无法使用白名单,请检查其解析的IP地址是否是内网地址,您应当避免外部请求内网地址

2.5.5 避免命令注入

应用程序可能存在这样的场景:获取客户端传递的参数,将参数组合到待执行的系统命令中。例如,下面示例中将函数参数作为系统命令的参数:

代码块

public class DoStuff {
  public string executeCommand(String userName){
    try {
      String myUid = userName;
      Runtime rt = Runtime.getRuntime();
      rt.exec("doStuff.exe " + ”-“ + myUid); // 执行doStuff.exe程序
            //  如果myUid为 "zhangsan && shutdown -s" 将会执行关机
      }catch(Exception e){
          e.printStackTrace();
      }
  }
}

您应当避免没有检查参数就将其带入到系统命令中,建议做如下检查:

如果可行,使用白名单检查参数是否匹配

避免参数值包含”&”, “&&”, “|”, “||”

2.5.6 避免任意文件上传

如果您的应用中需要使用文件上传,应当对上传文件进行限制:

检查上传文件后缀名,确保其在白名单列表中,并且保证所保存的文件后缀名在白名单列表中

设置保存文件的目录不具备可执行权限

随机化命名保存文件名

2.5.7 避免使用不安全的第三方组件

在您的应用中,可能会包含成百上千的第三方组件,应当避免使用不安全的组件(或其不安全的版本),特别包含严重和高危漏洞的组件。对于Java和Python的第三方组件评估,您可借助如下开源工具:https://github.com/SAP/vulnerability-assessment-tool

2.5.8 避免XML 外部实体引用

XML 外部实体引用(XML External Entities,XXE)是与解析XML消息相关的漏洞。XML允许外部实体引用,如下:

通过file协议应用/dev/randrom文件

<?xml version="1.0" encoding="ISO-8859-1"?>
  <!DOCTYPE foo [  
   <!ELEMENT foo ANY >
   <!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>

关于XXE更详细的介绍参考:https://www.owasp.org/images/5/5d/XML_Exteral_Entity_Attack.pdf https://security.tencent.com/index.php/blog/msg/69在您的业务场景中,也许需要接受客户端的XML消息,然后解析进一步处理业务(如微信公众号中部分与微信服务器的接口)。通常您所要处理的XML消息不需要使用到外部实体引用,因此在使用相关组件解析XML前禁用外部实体引用是非常推荐的做法。禁用外部实体引用往往仅需要简单的几行配置,不同的XML解析器做法不一,具体参考:https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md

2.5.9 保护Cookie安全

当应用在Cookie中存储敏感信息(如认证token),应当恰当保护。

2.5.9.1 设置Cookie HttpOnly

HttpOnly是设置Cookie时可以设置的一个属性,如果没有设置这个属性,该Cookie值允许被页面的脚本读取。Servlet示例如下:

代码块

//没有设置HttpOnly
response.setHeader("SET-COOKIE","token=" + token);
​
//设置HttpOnly
response.setHeader("SET-COOKIE","token=" + token + ";HttpOnly");
2.5.9.2 设置Cookie Secure

Secure是设置Cookie时可以设置的一个属性,如果您的应用网站时HTTPS的,可以设置此属性。这样浏览器就只会在访问协议为HTTPS的地址才会发送该Cookie。

代码块
Java
//没有设置Secure
response.setHeader(“SET-COOKIE”,”token=” + token + “;HttpOnly”);

//设置Secure
response.setHeader(“SET-COOKIE”,”token=” + token + “;HttpOnly;Secure”);
另外: 您也可以在Web容器中设置,如Tomcat7可以在/conf/web.xml 中设置

代码块

<session-config>
  <session-timeout>30</session-timeout>
  <cookie-config>
    <http-only>true</http-only>
    <secure>true</secure>
  </cookie-config>
</session-config>

不同的语言不通容器处理可能存在差异,请根据您所使用的找到对应的设置。

2.5.10 合理处理跨域

浏览器严格控制跨域,因为跨域可能会造成严重的信息泄露。然而,跨域访问的业务需求可能总是会存在。当您处理跨域时,务必保证允许被跨域访问的域是在白名单中的。例如,使用CORS(https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS)处理跨域,使用Filter处理:

代码块

String origin = httpServletRequest.getHeader("Origin");
if (Constants.ALLOWED_DOMAIN_List.contains(origin)) {
    httpServletResponse.setHeader("Access-Control-Allow-Origin", origin);
    httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    //...Ohter Header
}
if("OPTIONS".equalsIgnoreCase(httpServletRequest.getMethod())) {
    OutputStream out = httpServletResponse.getOutputStream();
    out.write("ok".getBytes());
    out.flush();
}else{
    filterChain.doFilter(httpServletRequest, httpServletResponse);
}
2.5.11 避免源码泄露

避免将您的源码存储在GitHub、云盘中等,源码泄露将会成为影响应用安全的威胁。

避免您的备份文件被下载,如果您要备份文件,确保备份文件不可从互联网下载。

2.5.12 废弃的接口及时下线

您可能使用诸如v1、v2等对接口进行版本管理,当您升级了接口版本之后,如果久接口已经废弃,请及时下线处理。因为当接口出现安全问题时,您可能只兼顾新版本,如果旧版本仍然开放,可能会成为被入侵的风险点。当进行接口下线处理时,仅使用@Deprecated注解标注时不够的,您需要进一步移除路由、或者删除源码。

作者:admin  创建时间:2022-03-04 11:17
最后编辑:admin  更新时间:2023-11-14 09:56