加密
单向加密
MD5
不多说了,全称Message Digest Algorithm 5,信息摘要算法
SHA
全称secure hash algorithm 安全散列算法
HMAC
hash message authentication code 散列消息鉴别码,根据hash算法的认证协议。
HMAC的认证原理是,使用一个密钥生成一 个固定大小的小数据块,即MAC,并将其加入消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。经常用于对API参数进行请求验证:分配给授权调用方一个 密钥,授权调用方使用密钥和接口的相关信息散列计算出请求签名,然后将签名连同数据-起发给服务 方;服务方根据调用方标识,使用其密钥和同样的散列算法计算出签名和传来的签名做比较,以验证请求的合法性。
对称加密算法
对称加密又称被为单密钥加密,是采用单钥密码系统的加密方法,同一个密钥既也可以解密。
DES
DES,全称Data Encryption Standard,即数据加密标准,其使用64位的密钥把64位的明文输人块经过16轮替换和移位操作后变为64位的密文输出块。此算法的人口参数有3个。
- Key: 8字节共64位,是DES算法的工作密钥,但DES实际使用其中的56位。
- Data: 8字节共64位,是要被加密或解密的数据。
- Mode: DES的工作方式,包括加密或解密。
AES
- AES是DES的升级版,相比于DES有一下特点:
- 运算速度快
- 对内存需求低
- 支持可变分组长度,分组长度可设定为32big任意背书,最小128,最大256
- 秘钥长度可以设定为32任意倍数,128~256
PBE
PBE,全称Password-Based Encryption, 基于密码加密,是一种简便的加密方式。密钥由用户自己掌管,不借助任何物理媒体,其采用salt杂凑多重加密等方法保证数据的安全性。
非对称加密算法
非对称加密需要两个密钥,一个是公开的,称为公钥;另一个是私有的, 称为私钥。公润用来加密数据,只有私钥才能解密;私钥般用来签名, 公钥用来验证签名。非对称加密算法安全性要比对称加密算法高很多,但是其运算消耗资源多、效率慢,因此很多情况下都是结合对称加密一起使用的。
RSA
RSA,是以算法发明者的名字命名的,其安全性依赖于大数分解的困难程度,于认证和数据加解密,也可以用于密钥交换。 其一般流程如下。
1)A构建一对密钥, 将公钢公布给B.将私街保留。
2)A使用私钥加密数据并签名,发送给B.
3)B使用A的公钥、签名来验证收到的密文是否有效,有效则使用A的公钥对数据解密。
4)B使用A的公钥加密数据,发送给A,A用自己的私钥解密
DH
DH,全称Dife Hellman算法,是一一个密 钥交换协议。其主要用来做密钥交换,一般不用来做认证和加解密数据。其般的使用流程如下。
1) A构建一对密钥,将公钥公布给B,将私钥保留。
2) B通过A公钥构建密钥对儿,将公钥公布给A,将私钥保留。
3) AB双方互通本地密钥算法。
4) AB双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以
可见相比RSA. DH要多发送一个DH公钥,并且其最终对数据的加解密依赖于本地付称加密算法。
HTTPS
很多时候后端应用都会直接提供HTTP接口以供浏览器、客户端、第三方来调用。但由于HTTP协议是明文传输的,且没有任何的身份认证机制和数据完整性保证,因此数据很容易被中间人劫持、监听、篡改等。虽然能够通过对传输的业务数据加密避免这点,但HTTPS才是最根本的解决方案。这也是现在好多互联网公司都在进行全站HTTPS迁移的原因,也是应用商店要求应用调用的API接口都换成HTTPS的动机所在。
可以看到,HTTPS相比HTTP多了一个安全加密层,不仅对数据进行了加密,还对数据完整性提供了保护,并且也提供了身份验证的功能。
非对称加密算法在很多情况下会与对称加密算法一起使用,而HTTP就是一个典型的应用场景。简单说就是:其中一方先生成一个对称加密密钥,然后通过对称加密的方式夹发送这个密钥,这样双方之后的通信就可以用对称加密这种高效率的法进行加解密了。
安全协议——SSL/TLS
SSL和TLS都是用于保障端到端之间连接的安全性的,位于应用层和传输层之间。SSL现在已经改名为TSL,主流版本为TLS1.2:
- 握手层:端与端之间协商密码、连接状态等连接参数,并完成身份验证。
- 记录层:对数据的封装,将数据交给传输层之前会经过分片、压缩、认证、加密等操作
证书中心——CA
CA是HTTPS依赖的关键组件,即Certifcate Authority,证书中心。客户端从CA获取服务器公钥,并能够保证此公钥不会被中间人篡改。
CA对公钥完整性保证依赖的一个机制就是颁发证书,证书包括以下内容。
- 证书的发布机构。
- 证书的有效期。
- 公钥。
- 证书所有人。
- 数字签名。
使用CA的流程如下。
1)首先将公钥与个人信息用hash算法生成一个消息摘要,然后CA再用它的私钥对消息摘要加密,最终形成数字签名。
2)客户端接收到证书时,用同样的hash算法再次生成一个消息摘要,然后用CA的公钥对证书进行解密,之后再对比两个消息摘要即可保证数据未被篡改。
此外,为了保证CA的权咸性以及其自身公钥的权威性,CA机构有一个树形结构,父节点是信用高的CA,会对子节点的CA做信用背书。
9.2.3请求交互过程
1)客户端向服务器端发送请求,将客户端的功能和首选项传送给服务器端,包括客户端支持的SSL版本、加密组件列表等。
2)服务器端发送选择的连接参数(从客户端加密组件中筛选出的加密组件内容和压缩方法)以及证书(包含公钥等信息)给客户端。
3)客户端读取证书中的所有人、有效期等信息并进行校验,然后通过预置的CA验证证书合法性,有问题则提示。
4) 客户端生成用于数据加密的对称密钥,然后用服务器的公钥进行加密并发送给服务器端。
5)服务器端使用自己的私钥解密数据,获得用于数据加密的对称密钥。
6) 安全的通道建立完毕,后续基于对称加密算法传输数据。
性能优化
虽然HTTPS安全性比HTTP要高很多,但是由于建立通信通道要先交互很多次,应用的性能受到了不小的影响,因此优化HTTPS的性能非常关键。
1)算法选择。
HTTPS的通信过程中有不少算法参与,算法的性能直接决定了HTTPS的性能。
- 数字签名:选择ECDSA算法,它的签名性能远超RSA,而且签名是在服务器端做的。服务器端发送给客户端的证书链包含所有中间证书。
- 密钥交换:ECDHE具有更好的性能,并且其支持前向保密(Forward Secrecy),可以避免中间人保存客户端和服务器端之间的通信数据,并且能开启TLS False Start。
- 对称加密:AES256-GCM-SHA384的性能比较好,建议选择此算法进行数据加密。
2)TLS缓冲区。
TLS缓冲区大小即一个TLS Record的大小,在Nginx中默认值是16KB。如果HTTP的数据是320KB,那么就会被拆分为20个TLS Record,然后每个TLS Record会被TCP层拆分为多个TCP包发送给客户端。
如果此值过小,那么TLS Record Head的负载就会增加,会降低连接的吞吐量;而如果此值过大,拆分出的TCP包就比较大,传输过程中容易出现丢包,整个TLS Record到达客户端的时间就会加长。
由于在TCP慢启动的过程中TCP连接的拥塞窗口CWND较小,TCP连接吞吐量也小,因此可以把TLS Record Size设置得小一点;而在TCP连接结束慢启动之后,吞吐量上来了,TLS Record Size 可以设置得大一些。
3) TLS False Start。
主要指的是客户端这边的TLS False Start。开启此选项,那么客户端在发送ChangeCipher Spec、Finished 之后,可以立即发送应用数据,无须等待服务器端的Change Cipherpec、Finished。这样,应用数据的发送实际上并未等到握手全部完成,从而节省出一个
RTT时间,可以提高一定的性能。但开启此选项,需要满足以下条件。
- 客户端和服务器端都需要支持NPN/ALPN(浏览器要求)。
- 需要采用支持前向保密的密码套件(ECDHE)。
web安全
Web安全问题,从大的方面可以分为:
- 客户端安全:通过浏览器进行攻击的安全问题。
- 服务器端安全:通过发送请求到服务器端进行攻击的安全问题。
常见的客户端安全问题有:
- 跨站点脚本攻击。
- 跨站点请求伪造。
- 常见的服务器端安全问题有:
- SQL注入。
- 基于约束条件的SQL攻击
- DDOS攻击。
- Session fixation。
跨站点脚本攻击
跨站点脚本攻击,全称Cross Site Script(XSS),顾名思义是跨越两个站点的攻击方式。
一般指的是攻击方通过“HTML”注人的方式篡改了网页,插入了恶意的脚本,从而在用户浏览网页或者移动客户端使用WebView加载时,默默地做了一些控制操作。
XSS可以说是客户端安全的首要问题,稍有不注意就会暴露出相关接口被人利用。
一个XSS攻击的例子如下。
- 一个Java应用提供了一个接口可以上传个人动态,动态内容是富文本的。攻击者上传的内容如下:
<img src="1" onerror="alert('attack')"/>
- 在服务器端和客户端程序未做任何过滤的情况下,当其他用户访问这个动态页面时,就会执行这个脚本。
如果脚本不是一个alert,而是换成跳转到一个具有删除操作的URL,或者脚本获取用户的Cookie,然后发送到远程服务器上,那么危害就会非常大。
防范这种攻击的常用方式有以下几种。
- 对任何允许用户输入的地方做检查,防止其提交脚本相关特殊字符串,如script、onload、onerror等。客户端和服务器端都要做检查。
- 做输入过滤,即将特殊字符都过滤掉或者换成HTML转义后的字符。在Java中可以使用 Apache Commons-Lang 中 StringEscapeUtils 的带escape 前缀的方法来做转义。
- 给Cookie属性设置上HttpOnly,可以防止脚本获取Cookie。
- 对输出内容做过滤。这个可以在客户端做,也可在服务器端做。服务器端主要就是转义HTML字符,客户端可以使用escape方法来过滤。
跨站点请求伪造
跨站点请求伪造,全称Cross Site Request Forgery,简称CSRF。这也是一种常见的攻击方式。
这种攻击方式,主要通过诱导用户单击某些链接,从而隐含地发起对其他站点的请求,进而进行数据操作。
一个攻击示例如下。
- 一个用户登录了一个站点,访问htpr/x/delete.notes?id=xx即可删除一个笔记。
- 攻击者在它的站点中构造一个页面,HTM1.页面含有以下内容:<img src="http://xx/delete_notes?id=xx"/>。当用户被诱导访问攻击者的站点时就发起了一个删除笔记的请求。
对于CSRF攻击的常用解决方案有以下几种。
- 对重要请求要求输入验证码,这样就能防止在用户不知情的情况下,被发送请求。
- 使用类似防盗链的机制,对header的 refer进行检验以确认请求来自合法的源。
- 对重要请求都附带一个服务器端生成的随机Token,提交时对此Token进行验证。这也是业界一个很普遍的做法。
SQL注入攻击
SQL注人攻击是一个很常见的攻击方式,原理是通过发送特殊的参数,拼接服务器端的SQL字符串,从而达到改变SQL功能的目的。
一个攻击例子如下。
- 服务器端登录验证使用下面的方式,其中userName和userPwd都是用户直接上传的参数。String sql= "select * from user where user_name = "+ userName + "and pwd ="+ userPwd;
- 用户提交userName为admin'-,userPwd为字符串xxx(由用户确定)。
- 拼接好之后的SQL语句变成了:select*from user where user_name ='admmin'-'andpwd= 'xxx'(-为SQL语句的注释),这样只要存在 user_name为admin的用户,此语句就能成功执行并返回admin用户的信息。
需要说明的是,如果服务器的请求错误信息没有做进一步封装,直接把原始的数据库错误返回,那么有经验的攻击者通过返回结果多次尝试就会有机会找出SQL注人的机会。
防范这种攻击的方案有以下几种。
- 在Java 中构造SQL查询语句时,杜绝拼接用户参数,尤其是拼接SQL查询的where条件。全部使用PreparedStatement预编译语句,通过?来传递参数。
- 在业务层面,过滤、转义SQL特殊字符,Apache Commons-Lang 中的StingEscapeUtil提供了escapeSQL功能(最新的Lang3已经删除此方法,因为其只是简单地替换为”)。
基于约束条件的SQL攻击
基于约束条件的SQL攻击的原理如下。
- 在处理SQL中的字符串时,字符串末尾的空格字符都会被删除,包括WHERE子句和INSERT语句,但LIKE子句除外。
- 在任意INSERT查询中,SQL会根据varchar(n)来限制字符串的最大长度,即超过n个字符的字符串只保留前n个字符。
如此,我们设计一个用户表(暂且忽略设计的合理性),对其中的用户名和密码字段都设置25个字符限制:
CREATE TABLE test user (user name varchar(25),
pwd varchar(25)
);
有一个user_name为user_test的用户注册,于是向数据库添加一条记录:
insert into test_user values("user test","111111");
接着,一个user_name为“user_test 1”(中间留有25个空格)的用户再来注册。一般的业务逻辑如下。
- 判断用户名是否存在。
select * from test_user where user_name = 'user_test 1'因为查询语句不会截断字符串,因此这样获取不到记录,表示用户不存在。 - 用户名不存在,那么插入新用户。
insert into test_user values("user_test 1","123456")
这样,由于user_name限制为25个字符,那么新用户的user_name成为了“user test”(后面是16个空格字符)。现在数据库记录如下(第二个记录后面是16个空格):
user_name pwd
user_test 111111
user_test 123456
这样,当使用user_name='user_test'和pwd='123456'登录时,能匹配到年二条记录,登录是成功的。但是用户信息使用的是第一条记录,于是攻击者就获取到了巢一个用户的操作权限。
防范这种攻击的措施如下。
- 为具有唯一性的那些列添加UNIQUE索引。
- 在数据库操作前先将输人参数修剪为特定长度。
分布式拒绝服务攻击——DDOS
DDOS,全称Distributed Denial of Service,分布式拒绝服务攻击。攻击者利用很多台村器同时向某个服务发送大量请求,人为构造并发压力,从而使得服务被冲垮,无法为正常用户提供服务。常见的DDOS攻击包括:
- SYN flood。
- UDP flood。
- ICMP flood。
其中SYN food是最经典的DDOS攻击。其利用了TCP连接三次握手时需要先发送SYN的机制,通过发送大量SYN包使得服务器端建立大量半连接,这就消耗了非常多的CPU资源和内存。针对这种攻击,很多解决方案是在TCP层就使用相关算法识别异常流量直接拒绝建立连接。但是,如果攻击者控制很多机器对一个资源消耗比较大的服务接口发起正常访问请求,那么这个方式就无效了。
由于难以区分是否是正常用户的请求,因此DDOS是非常难以防范的,但仍有一些措施能够尽量地减少DDOS带来的影响,介绍如下。
- 合理使用缓存、异步等措施提高应用性能。应用抗并发的能力越强,就越不容易被DDOS冲垮服务。
- 合理使用云计算相关组件,自动识别高峰流量并做自动扩容。
- 在应用中限制来自某一D或者某一设备ID的请求频率。超过此频率就将其放入黑名单,下次请求直接拒绝服务。Iara中可以通过Reds的incr和expire 操作来达到。如下:
String ip = Networkoti1.getclientIP (reqguest, false); // 获取 客户 端IP地址 String key="ddos."+ip; long count = suishenRedisremplate.incr(key);//incr 不会影响expire if (count > 10000){ throw new AccessException("access too frequently with ip:"+ StringUtils.defaultString(ip)); } else { if (count == 1)( suishenRedisTemplate.expire(key,10); return true; }
上述代码即可将同一IP的请求限制在10秒10000次。
此逻辑越靠近访问链路的前面效果越好,比如直接在Nginx中拦截,其效果就要比在业务应用中做得好。
会话固定攻击-——Session fixation
Sesion fxation 攻击,顾名思义就是会话固定攻击。在我们平时的Web开发中都是基于Sesion做用户会话管理的。在浏览器中,Session的ID一般是存储在Cookie中的,甚至直接附带在query参数中。如果Session 在未登录变为登录的情况下不发生改变的话,Sessionfixation 攻击就形成了。
一个攻击示例如下。
- ·击者进入网站http://xx.com。
- ·击者发送http://xx.com?JSESSIONID=123456给一个用户。
- 用户单击此链接进入网站,由于URL后面有JSESSIONID,因此直接使用它作为Session 的 ID。
- 用户成功登录后,攻击者就可以利用伪造的SessionID获取用户的各种操作权限。
这种攻击的关键点就在于Tomcat使用JSESSIONID作为Session ID。因此,防范这种攻击的核心之一就在于,不能使用客户端传来的Session ID。此外还有以下方法。
- 不要接受由GET或者POST参数指定的Session ID值。
- 针对每一个请求都生成新的Session。
- 只接受服务器端生成的Session ID。
- 为Session指定过期时间。