2 Star 1 Fork 0

zhrun8899 / learning-notes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
应用安全性.md 19.59 KB
一键复制 编辑 原始数据 按行查看 历史

应用安全性

服务端通信安全攻防详解

base64

DES

也是一种非常常用的加密方案,我们会将敏感的信息在通信过程中通过DES进行加密传输,然后在客户端和服务端直接进行解码。

此时,作为读者的你,可能会有个疑问,那如何保管密钥呢?其实,想想,答案就复出水面了,因为客户端和服务端都需要进行解码,所以两者都要存一份密钥。其实,还有一种方案是通过服务端下发,但是下发的时候通信的安全性也是没有很好的保障。

所以,DES对称加密也是存在一定的安全隐患:密钥可能会泄漏。这边,举个真实的案例,某个APP的资源不错,同事想抓包分析下其服务端通信的信息结构,但是发现它既然全部采用了DES加密方案,本来想放弃了,但是我们又回头想想客户端肯定需要密钥对接口的加密的内容做解码才能正常展现,那么密钥肯定在app包中,因此我们又对app进行了反编译,结果成功的获取到了密钥,对服务端通信的加密信息进行了解码。

AES对称加密

AES和DES类似,相较于DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高。一般情况下,用于文件的加密。我们之前做个不准确测试,AES和DES分别对一个大文件加密,AES的速度大概是DES的5倍。(因为基于工具和环境问题,这个数据不是很准确哟)。

仍然存在一个相同的问题:密钥可能会泄漏。因此,保管好密钥很关键。

升级到HTTPS

HTTPS的价值在于: 内容加密,第三方无法窃听。 身份认证,一旦被篡改,通信双方会立刻发现。 数据完整性。防止内容冒充或者篡改。 这个方案,没法保护敏感数据,如果需要对敏感数据进行加密,还是需要考虑加密方案。

URL签名

基于OAuth2协议,进行URL签名。这个方案,有很多话题可以分享 值得注意的是,URL签名只能垂直权限管理,但没法保护敏感数据,如果需要对敏感数据进行保护,还是需要考虑加密方案。

双向RSA加密

RSA双向认证,就是用对方的公钥加密是为了保密,这个只有对方用私钥能解密。用自己的私钥加密是为了防抵赖,能用我的公钥解开,说明这是我发来的。

例如,支付宝的支付接口就是非常典型的RSA双向认证的安全方案。此外,我们之前的教育资源、敏感验证码出于安全性考虑都借鉴了这个方案

HTTPS降级攻击

设计和实现 SSL/TLS 协议出现了漏洞,导致攻击者同样可以攻击一些旧版本的 SSL/TLS 协议。这其中就包括 SSL 3.0。 攻击者可利用 SSL 3.0 漏洞获取安全连接当中某些是SSL3.0加密后的明文内容。因为兼容性问题,当浏览器进行 HTTPS 连接失败的时候,将会尝试使用旧的协议版本,于是,加密协议由更加安全的协议,比如 TLS 1.2降级成 SSL 3.0。

如果服务器提供有漏洞的 SSL 3.0 协议的支持,同时,攻击者又能作为中间人控制被攻击者的浏览器发起漏洞版本的 HTTPS 请求,那虽然攻击者监听到的也是加密过的数据,但因为加密协议有漏洞,可以解密这些数据。攻击者可以利用此漏洞,截获用户的隐私数据,比如 Cookie,这样攻击者就可以拿到这些隐私数据,进行更深层次的攻击,进而造成了用户隐私的泄漏。

解决之道

目前,唯一解决问题的方法是禁用 SSL 3.0 加密协议,防止TLS 1.2 或者 TLS 1.1 或者 TLS 1.0降级到 SSL 3.0 加密协议。

禁用的策略有很多,这里主要讲解下 Nginx 如何防止 TLS 降级到 SSL 3.0 以下版本,从而防止 HTTPS 降级攻击。

原先的配置如下。值得注意的是,隐性默认是SSLv3 TLSv1 TLSv1.1 TLSv1.2。

ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; 禁用的操作很简单,现在改成这样即可。 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

STRIDE 威胁

STRIDE 威胁,代表六种安全威胁:身份假冒(Spoofing)、篡改(Tampering)、抵赖(Repudiation)、信息泄露(Information Disclosure)、拒绝服务(Denial of Service)、特权提升(Elevation of Privilege)。

身份假冒(Spoofing)

身份假冒,即伪装成某对象或某人。例如,我们通过伪造别人的 ID 进行操作。

篡改(Tampering)

篡改,即未经授权修改数据或者代码。例如,我通过网络抓包或者某种途径修改某个请求包,而服务端没有进行进一步的防范措施,使得我篡改的请求包提交成功。

抵赖(Repudiation)

抵赖,即拒绝执行他人无法证实也无法反对的行为而产生抵赖。例如,我攻击了某个产品,他们并不知道是我做的,没有证据证明是我做的,我就可以进行抵赖,换句话说,我可以死不承认。

信息泄露(Information Disclosure)

信息泄露,即将信息暴露给未授权用户。例如,我通过某种途径获取未经加密的敏感信息,例如用户密码。

拒绝服务(Denial of Service)

拒绝服务,即拒绝或降低有效用户的服务级别。例如,我通过拒绝服务攻击,使得其他正常用户无法使用产品的相关服务功能。

特权提升(Elevation of Privilege)

特权提升,即通过非授权方式获得更高权限。例如,我试图用管理员的权限进行业务操作。

安全要素 为了防范上面的 STRIDE 威胁,我们需要采用一些防范措施。

威胁 安全要素 消减技术 身份假冒 认证 Kerberos、SSL/TLS、证书、认证码等 篡改 完整性 访问控制列表、SSL/TLS、认证码等 抵赖 非抵赖/审计/记录 安全审计和日志记录、数字签名、可信第三方 信息泄露 保密 加密、访问控制列表 拒绝服务 可用性 访问控制列表、过滤、配额、授权 特权提升 授权 访问控制列表、角色控制、授权

全的软件开发生命周期

静态代码分析

静态代码分析的好处在于,测试可以完全自动化,使开发人员能够实现安全的编码实践,并在系统发布前,检查并修复存在风险的安全问题。

静态代码分析工具可以帮助开发人员快速查找和防止 SQL 注入、跨站脚本(XSS),跨站请求伪造(CSRF)和其他恶意攻击。

工具

Sonar (SonarQube)就是一个很好的工具。Sonar 是一个用于代码质量管理平台,管理源代码的质量。Sonar 不只是一个质量数据报告工具,更是代码质量管理平台。支持的语言包括:Java、PHP、C#、C、Cobol、PL/SQL、Flex 等。

服务端的编码质量

从简洁的代码开始

具有良好的代码规范

需要团队定义一整套规范,包括注释,包名,类名,字段名,代码结构等等,从而保证代码清晰,良好的格式。

保证注释的合理性和正确性

保证注释的合理性和正确性,这个也是很重要的。经常,我们不去注意注释,从而导致了重要复杂业务注释不全,或者注释没有及时更新,给后来的人挖坑。个人觉得,添加注释的过程,就是业务代码梳理的过程。

测试

单元测试

在编码阶段,我们就需要完成单元测试,保证提测前,做好单元测试,即在交付测试环境之前过完一轮。这样,可以非常有效减少在测试过程中出现BUG的概率。 单元测试的用例应该包括:功能可用性、功能正确性、等价值、边界值。 QA的测试用例,bug反馈,可以整理到单元测试中。 通过检查工具,保证单元测试的覆盖率,例如Jacoco。4

服务端错误手册

根据项目的情况,整理服务端错误手册,手册在手,天下我有的情怀。

考虑代码复用

尽量少去造轮子,重复的代码,考虑是否可以抽离,是否可以组件化。

代码审核,必须保证

我们团队正常会做三重审核机制。

代码交叉评审:开发好的代码,给服务端其他人评审。 经理代码评审 代码例会评审:不定期的开展例会,将自己开发的功能,进行分享和讲解,服务端的同学一方面对其他人的功能有所了解,同时走查他的代码,审核是否有问题。一个重要的好处就是,及时发现潜在问题。

服务端评审点

审核点,我整理了下大概有重要的包括几个部分。

  • 代码规范。
  • 有效性检验:是否考虑边界值、合法数据等。
  • 功能逻辑:功能是否偏差等。
  • 性能问题:是否存在性能问题,例如SQL慢查询。
  • 安全问题:是否存在SQL注入,是否存在XSS攻击,是否鉴权等。
  • 接口是否可用:可以使用postman,dhc(chrome 插件)等工具模拟请求,进行测试。

登录方式的变迁

在传统的 MVC 模式中,一般使用 Cookie + Session 保持用户的登录状态。其中,当用户首次访问服务器的时候,服务器为每个用户单独创建一个 Session 对象,并分配一个新的 SessionID,此时 SessionID 通过 Cookie 保存在客户端。当用户再次访问服务器的时候,携带保存 SessionID 的 Cookie 给服务器,服务器查询是否存在这个 SessionID,如果存在,即认为用户处于登录状态,如果没有对应的 SessionID,服务器会给分配一个新的 SessionID。

当前后端分离后,服务端的 API 设计一般是无状态的,因此不能使用 Cookie + Session 保持用户的登录状态。此时,就需要使用 Token 令牌。服务端接收到前端发送的用户名和密码后,验证用户名和密码是否正确。如果用户名和密码不正确,则返回错误信息。如果用户名和密码正确,则生成一个随机且不重复的 Token 令牌,这个 Token 令牌是用户身份的唯一标识。一般情况下,前端将 Token 令牌保存到 Cookie 中,并设置 HttpOnly 属性。当用户退出系统时,前端调用服务端的“用户注销”接口,销毁 Token 令牌。

Oauth2 协议的授权与认证原理

OAuth 是一个关于授权的开放网络标准,目前的最新版本是 OAuth 2.0,不兼容 OAuth 1.0。OAuth 2.0 允许第三方网站在用户授权的前提下访问用户在服务商那里存储的各种信息。这种授权无需将用户提供用户名与密码提供给该第三方网站。实际上,OAuth 2.0 允许用户提供一个令牌给第三方网站,一个令牌对应一个特定的第三方网站,同时该令牌只能在特定的时间内访问特定的资源,用户在客户端使用用户名和密码在用户中心获得授权,然后客户端在访问应用是附上 Token 令牌。此时,应用接收到客户端的 Token 令牌到用户中心进行认证。

RBAC

基于角色的访问控制,英文是 Role-Based Access Control,简称 RBAC。它通过建立用户与角色的对应关系,使得每个用户可以拥有多个角色,每个角色可以拥有多个权限。基于角色的访问控制会定义多个不同的角色,不同角色实际上就是一个权限的集合。基于角色的访问控制中,不同角色之间具有高低之分,高权限角色可以访问低权限角色的资源,但是低权限角色往往不能访问高权限角色的资源。举个例子,一个教育性质的作业系统中存在老师角色与学生角色,老师角色与学生角色都具有查看作业的权限,但是学生角色不具有审批作业的权限,只有老师角色才具有审批作业的权限,如果学生角色可以进行这个操作,那么可能存在越权访问。同时,基于角色的访问控制遵守最小特权,应该授予所需要的完成其任务的最小角色,这样可以防止用户干坏事。

RBAC 是一种“用户-角色-权限”的授权模型,主要分为 RBAC0 基本模型、RBAC1 角色的分层模型、RBAC2 约束模型、RBAC3 统一模型。其中,RBAC0 是 RBAC 的核心,包括用户、角色、权限和会话。RBAC1 基于 RBAC0 进行扩展,是 RBAC 的角色分层模型,引入角色继承概念。RBAC2 基于 RBAC0 进行扩展,引入互斥角色的限制,互斥角色是指各自权限互相制约的两个角色,此外,还约束一个用户拥有的角色是有限的,一个角色拥有的权限是有限的,以及想要获取较高权限,首先需要拥有一个低级权限。RBAC3 基于 RBAC0 的基础上,将 RBAC1 和 RBAC2 进行整合,因此 RBAC3 是一种既有角色分层又有约束的一种模型。

基于数据的访问控制 DBCA

DBCA通过业务逻辑进行 基于角色的访问控制,只验证访问数据的角色,但是没有对角色内的用户做细分。举个例子,用户甲与用户乙都具有用一个角色,但是如果只建立基于角色的访问控制,那么用户甲可以对用户乙的数据进行任意操作,从而发生了越权访问。因此,在业务场景中仅仅使用基于角色的访问控制是不够的,还需要引入基于数据的访问控制。如果将基于角色的访问控制视为一种垂直权限控制,那么,基于数据的访问控制就是一种水平权限控制。在业务场景中,往往对基于数据的访问控制不够重视,举个例子,评论功能是一个非常常见的功能,用户可以在客户端发起评论,回复评论,查看评论,删除评论等操作。一般情况下,只有本人才可以删除自己的评论,如果此时,业务层面没有建立数据的访问控制,那么用户甲可以试图绕过客户端,通过调用服务端RESTful API 接口,猜测评论 ID 并修改评论 ID 就可以删除别人的评论。事实上,这是非常严重的越权操作。除此之外,用户之间往往也存在一些私有的数据,而这些私有的数据在正常情况下,只有用户自己才能访问。 基于数据的访问控制,需要业务层面去处理,但是这个也是最为经常遗落的安全点,需要引起重视。这里,再次使用删除评论的案例,通过 Java 语言进行介绍。在这个案例中,核心的代码片段在于,判断当前用户是否是评论的创建者,如果是则通过,不是则报出没有权限的错误码。那么,这样就可以很好地防止数据的越权操作。

提高服务端编码质量 - 用例检查列表

提高服务端编码质量,对我们的编码进行Code Review十分重要,今天我整理下我在开发过程中的历史经验,整理了一份检查列表,欢迎大家一起来补充和完善。

查询

###分页显示 检查分页功能是否正常,分页边界是否有矫正机制,例如非数值类型,下限是否校验,上限是否设置允许最大值等。

数据一致性

查询数据是否一致,这种情况不一致可能是接口错误,或者存在缓存。

返回总数是否正确,这个经常会被忽略。

分类排序

是否有进行排序功能,排序是否符合需求,例如需求是要根据热度排序,接口返回按更新时间排序明显就和需求有偏差了。

模糊查询

是否是模糊查询,还是精确查询。

特殊字符是否过滤,例如MySQL的特殊字符:“&”和“_”。

查询的性能问题,

MySQL的模糊查询走全表,所以客户端接口一定要确认性能是否有影响。客户端接口对性能有要求,建议使用Elasticsearch、Solr等全文搜索。

查询条件

开始时间和结束时间的边界 关键字对于特殊字符、空字符串、超长字符、数字边界等约束。

新增

是否必填

对于强制输入的字段,是否必填,错误信息是否正确。

字符长度

最长最短长度都要测。举个例子,比如数据库的一个字段类型是text,觉得需要测试它的上限么?答案是:要。一个真实案例,一个文章的内容一不小心可能就超过65535的上限,这个时候接口就出现500的错误咯。

数字边界

对于数字型的字段,测试上下边界非常重要。经常我们会忽略这点,举个例子,超过Integer上限并不是我们想象的那么遥不可及。

合法数据

如枚举类型(1-上架;2-下架),电话号码、电子邮箱、时间格式等。

特殊字符

特殊字符允不允许(业务决定),会不会导致数据库报错和乱码 是否存在SQL注入的可能。 是否存在xss攻击的可能。

带空格的字段

服务端是否有做trim操作,只输入空格是否正确保存。

上传功能

上传的文件是否可以使用,上传的文件格式是否有限制等。

重复添加

是否输入字段不能输入重复的数据,是否区分大小写的情况,如果输入重复数据,程序不能奔溃并且错误的提示信息正常(正常是409错误码)。

修改

修改接口检验标准和新增接口类似。

是否必填

对于强制输入的字段,是否必填,错误信息是否正确。

字符长度

最长最短长度都要测。举个例子,比如数据库的一个字段类型是text,觉得需要测试它的上限么?答案是:要。一个真实案例,一个文章的内容一不小心可能就超过65535的上限,这个时候接口就出现500的错误咯

数字边界

对于数字型的字段,测试上下边界非常重要。经常我们会忽略这点,举个例子,超过Integer上限并不是我们想象的那么遥不可及。

合法数据

如枚举类型(1-上架;2-下架),电话号码、电子邮箱、时间格式等。

特殊字符

特殊字符允不允许(业务决定),会不会导致数据库报错和乱码 是否存在SQL注入的可能。 是否存在xss攻击的可能。 带空格的字段 服务端是否有做trim操作,只输入空格是否正确保存。

重复修改

修改不存在的数据:是否有合理的错误提示。(正常是404错误码)。 修改合理数据:是否修改

删除

删除不存在的数据

是否有合理的错误提示。

删除合法数据

这个有几个Code Review点

是否删除成功(数据层面)

删除后数据库应该是查不到的。(这个特别注意缓存的同步问题) 是真删除,还是伪删除。 删除后可以添加同样的数据记录。

不允许删除的数据

因为业务的需求,有些数据正在使用,所以不允许删除。根据业务情况,进行分析。

删除数据的衍生影响

例如这个记录在其他表由被引用到,互联网产品一般情况下不用外键,所以要特别注意,衍生数据的影响和处理机制。

数据导出

为了减少服务端的压力,对于报表导出的数量需要进行限制,例如一次只能导出 5 万条记录,并且建议用户分批导出。

此外,如果数据源都是在存放在当前系统中,那么处理起来就方便地多,只需要通过 JDBC 获取到数据源并且进行 Excel 的生成与渲染。然而,如果部分数据源存储在外部系统中,那么就需要 RPC 调用或者 RESTful API 调用才能获取到。这样,一方面会很大影响到性能,另一方面可能存在接口调用超时。此时,优先考虑将数据冗余到本地,其次折中的处理方案是,调用失败或者调用超时进行重试来实现数据补偿,并且在重试之后无法获取到某些外部数据时,进行一个友好的提示,例如“系统太累了,暂时没有取到哟”。

有时,报表导出等待时间太久会导致 Nginx 超时,我们可以将报表导出改变成异步方式,当用户发起报表导出请求后,服务端立即响应应答,并异步执行 Excel 的生成与渲染。当完成任务时,通过消息队列或者心跳包机制通知前端进行下载。

1
https://gitee.com/zhrun8899/learning-notes.git
git@gitee.com:zhrun8899/learning-notes.git
zhrun8899
learning-notes
learning-notes
master

搜索帮助