扫盲——加密那些事

  created  by  鱼鱼 {{tag}}
创建于 2021年05月06日 20:16:23 最后修改于 2021年05月14日 11:42:21

    扫盲加密解密算法。

算法分类:散列算法?编码?加解密?

    日常开发中我们经常接触MD5算法,以此进行简单的文件完整性校验或者是后台密码验证,MD5是最常见也是最简单快捷的散列算法,常用于参数或文件完整性校验,譬如网络请求发起方与接收方分别对参数做MD5编码,一旦不一致便判断请求被篡改从而拒绝该请求,从而保证信息安全,编码后的字符串是编码前文本的一个简要梗概,因此它也被称作是信息摘要算法。这个算法的特点就是不可逆,只用于信息准确性和防篡改的校验,当然,MD5作为老牌的散列算法,很多经典的编码已经可以被反向解码出来(依靠正向的暴力穷举)以及被碰撞模仿(王小云院士团队的"破解"能够根据MD5编码后串码模拟原始消息,即使它可能与原信息不同),类似的还有SHA1,因此衍生了SHA224SHA256SHA512等更多安全的散列算法。当我们进行文件完整性校验等操作时,使用MD5一般没有问题,但进行密码或参数校验时,尽量选取更加安全的散列算法。

    上面提到最常见的两类信息摘要算法:MD系列和SHA系列。有人考虑到一些原始明文过于简单,会在明文的基础上做"加盐"操作,salt通常是一串随机的乱码,每次加在原始明文中,使之不容易被破解。考虑到这一点,有人索性结合salt发明了有秘钥的散列算法HMAC(即使有秘钥加入,仍是不可逆的散列算法),他在MD和SHA系列摘要基础上添加了一串秘钥,进一步提高了安全性,也基本不存在"被破解"的问题。根据散列算法不同,又分为HMAC-SHA1、HMAC-SHA224等。

    这里我们暂且提一下BASE64,这是一种传输编码方式,只是经常被混淆为"加密算法",事实上,它与加解密毫不沾边,BASE64是为方便在数据传输中传输二进制的数据,可以通过BASE64正反向编码,因为常规的文本编码(例如UTF8)可能有不存在的字符集导致乱码从而丢失信息。

    以上提到的算法虽然经常被称作加密算法,但确实不算真正的加密算法,真正的加密都兼有信息的加密和解密过程,加密表示通过一个秘钥和一段明文利用指定的加密算法获取密文的过程,即:

cipher =  f(secret, plain)          cipher、f()、secret、plain分别代表密文、加密函数、加密用秘钥和明文

    解密恰巧是这一等式的逆向过程,即

plain = f₁(secret₁, cipher)                       f₁、secret₁分别代表解密函数、解密用的秘钥

    函数不一致很容易理解,所用秘钥也是可以不一致的,如果加解密使用的是同一秘钥,秘钥长度为56bit,加密算法会被称为对称加密,代表加密算法为DESAESRC2RC4等,同时也存在着一些加解密所用秘钥不同的加密算法,他们被称为非对称加密,这一算法的加解密秘钥需要成对的使用,分别为公钥和私钥,一般公钥是会对外公开的,私钥则不能,这样保证加解密的全过程不会暴露,保护了私钥本身的安全性。一个代表是RSA加密。

散列算法

    上文已经提到,散列算法也叫信息摘要算法。对于不同的输入,其输出也不同,碰撞概率(不同原文有相同的编码)极其微小。但对于同一个算法,输出一般都是定长的。

    MD5一般会用于文件完整性校验:

    或是小型系统的账号密码校验:

    对请求参数的校验以防止篡改:

    一般会对在编码前对密码加salt,普遍会选取用户的用户名,所以在用户修改用户名前也要进行密码校验以重新生成编码。

    SHA-1一般与MD5用处类似,直到后面推出了SHA2系列(根据编码后的长度分为SHA224、SHA256、SHA512等),以及配合了秘钥的HMAC系列算法,被广泛用于校验请求的数字签名(数字签名我们之后再提)中,以上MD5的职能他们当然也同样能承包,相应的,更好的安全性往往会带来更差的性能,性能敏感系统一般不会使用太过于复杂的散列算法。

加密算法

    上文也提到了,本质上,散列算法不属于加密算法,加密一般是为了保证明文在网络传输过程中的安全性,所以往往需要解密过程,譬如上文中用户登录场景,如果在很容易暴露网络请求包的场景下,可以直接对请求内容进行加密,从而无法被查看和篡改。

    有些人可能注意到这与Https的目标类似,https协议本身能在未授权的情况下保证客户端发出信息的安全,任何一方在没有合法证书的情况下是不能直接获取请求内容的。采取加密算法对请求参数进行加密的目的不止于此,使用加密的作用要比https协议更多,应用更广,譬如当我们作为客户端使用者,但开发者想要对请求细节进行隐藏从而避免被模仿,此时我们通过Https是能获取到请求参数的,因为请求是由我们这一方发起的,装载证书抓包即可,但如果使用非对称加密,即使我们拥有公钥,也永远无法解密得知实际的请求内容。

    在Java程序中使用加密不难,在此不予举例,通常使用较多的是AES和RSA加密方式,需要注意的是,如果我们要使用AES256加密,需要额外下载jdk中的jar文件并进行替换,默认的jdk并不支持256位的AES加密。可以从以下网址下载:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html,下载会得到一个zip包,将里面的local_policy.jar和US_export_policy.jar解压到JDK安装目录\jre\lib\security下覆盖原文件即可,独立JRE的话也是覆盖相同路径的文件。

数字签名

    数字签名是一种公认的比较好用的防止数据篡改、保证服务数据安全的手段,除去对调用方的校验、还有对请求时间和请求体的全方面验证,最大程度确保了数据的完整性和安全。数字签名也是OpenAPI常用的手端之一,数字签名主要有以下几个要素:

  • 代表当前请求的时间

  • 代表请求的调用方,通常是一段代表性的key

  • 请求体的一段信息摘要,譬如对请求体的MD5加密

  • 请求内容的加密段,数字签名的实际所指,实际的请求体可以不是加密的,与此无关

最佳实践

    结合以上几个要素,我们在这里可以设计一个比较通用的数字签名:

  • 请求时附加请求时间戳,至少精确到秒级;

  • 约定一个key(appKey),客户端和服务端共同记录,可以标识请求来源;

  • 约定一个secret,用于签名加密的秘钥使用,可选的使用对称或者非对称加密或者信息摘要算法;

  • 约定一个信息摘要算法,请求时对请求内容(譬如get参数、post请求体)进行编码并传输;

  • 每次请求对以上内容进行加密,密文同步传出,可以使用加密或者HMAC算法,这个字段一般被称作签名(sign)。

    而在服务端,也需要校验以下内容:

  • 验证请求时间是最近一分钟(根据实际可能的网络延迟进行调整),避免 请求重放

  • 验证各个字段以及对请求内容做摘要算法验证;

  • 进行同步加密(如果是HMAC),或者信息解密(如果是加密)并验证。

当以上都验证通过,此时可以判定这是绝对安全的消息。

附:公私钥的使用

    非对称加密中,一般公钥是可以公开的,私钥是程序内部或后台保密的。这就注定公私钥的使用在加密和数字签名两种场景中使用方式也是不同的,在加密场景下,采用公钥加密,私钥解密的方式,只有服务端可以读取密文原文。但在签名验证中,这一过程恰好是相反的,服务端不希望签名被篡改和模仿,因此私钥往往是用来加密的,用来验证的公钥则公开,采用公钥解密,私钥加密的方式。

评论区
评论
{{comment.creator}}
{{comment.createTime}} {{comment.index}}楼
评论

扫盲——加密那些事

扫盲——加密那些事

    扫盲加密解密算法。

算法分类:散列算法?编码?加解密?

    日常开发中我们经常接触MD5算法,以此进行简单的文件完整性校验或者是后台密码验证,MD5是最常见也是最简单快捷的散列算法,常用于参数或文件完整性校验,譬如网络请求发起方与接收方分别对参数做MD5编码,一旦不一致便判断请求被篡改从而拒绝该请求,从而保证信息安全,编码后的字符串是编码前文本的一个简要梗概,因此它也被称作是信息摘要算法。这个算法的特点就是不可逆,只用于信息准确性和防篡改的校验,当然,MD5作为老牌的散列算法,很多经典的编码已经可以被反向解码出来(依靠正向的暴力穷举)以及被碰撞模仿(王小云院士团队的"破解"能够根据MD5编码后串码模拟原始消息,即使它可能与原信息不同),类似的还有SHA1,因此衍生了SHA224SHA256SHA512等更多安全的散列算法。当我们进行文件完整性校验等操作时,使用MD5一般没有问题,但进行密码或参数校验时,尽量选取更加安全的散列算法。

    上面提到最常见的两类信息摘要算法:MD系列和SHA系列。有人考虑到一些原始明文过于简单,会在明文的基础上做"加盐"操作,salt通常是一串随机的乱码,每次加在原始明文中,使之不容易被破解。考虑到这一点,有人索性结合salt发明了有秘钥的散列算法HMAC(即使有秘钥加入,仍是不可逆的散列算法),他在MD和SHA系列摘要基础上添加了一串秘钥,进一步提高了安全性,也基本不存在"被破解"的问题。根据散列算法不同,又分为HMAC-SHA1、HMAC-SHA224等。

    这里我们暂且提一下BASE64,这是一种传输编码方式,只是经常被混淆为"加密算法",事实上,它与加解密毫不沾边,BASE64是为方便在数据传输中传输二进制的数据,可以通过BASE64正反向编码,因为常规的文本编码(例如UTF8)可能有不存在的字符集导致乱码从而丢失信息。

    以上提到的算法虽然经常被称作加密算法,但确实不算真正的加密算法,真正的加密都兼有信息的加密和解密过程,加密表示通过一个秘钥和一段明文利用指定的加密算法获取密文的过程,即:

cipher =  f(secret, plain)          cipher、f()、secret、plain分别代表密文、加密函数、加密用秘钥和明文

    解密恰巧是这一等式的逆向过程,即

plain = f₁(secret₁, cipher)                       f₁、secret₁分别代表解密函数、解密用的秘钥

    函数不一致很容易理解,所用秘钥也是可以不一致的,如果加解密使用的是同一秘钥,秘钥长度为56bit,加密算法会被称为对称加密,代表加密算法为DESAESRC2RC4等,同时也存在着一些加解密所用秘钥不同的加密算法,他们被称为非对称加密,这一算法的加解密秘钥需要成对的使用,分别为公钥和私钥,一般公钥是会对外公开的,私钥则不能,这样保证加解密的全过程不会暴露,保护了私钥本身的安全性。一个代表是RSA加密。

散列算法

    上文已经提到,散列算法也叫信息摘要算法。对于不同的输入,其输出也不同,碰撞概率(不同原文有相同的编码)极其微小。但对于同一个算法,输出一般都是定长的。

    MD5一般会用于文件完整性校验:

    或是小型系统的账号密码校验:

    对请求参数的校验以防止篡改:

    一般会对在编码前对密码加salt,普遍会选取用户的用户名,所以在用户修改用户名前也要进行密码校验以重新生成编码。

    SHA-1一般与MD5用处类似,直到后面推出了SHA2系列(根据编码后的长度分为SHA224、SHA256、SHA512等),以及配合了秘钥的HMAC系列算法,被广泛用于校验请求的数字签名(数字签名我们之后再提)中,以上MD5的职能他们当然也同样能承包,相应的,更好的安全性往往会带来更差的性能,性能敏感系统一般不会使用太过于复杂的散列算法。

加密算法

    上文也提到了,本质上,散列算法不属于加密算法,加密一般是为了保证明文在网络传输过程中的安全性,所以往往需要解密过程,譬如上文中用户登录场景,如果在很容易暴露网络请求包的场景下,可以直接对请求内容进行加密,从而无法被查看和篡改。

    有些人可能注意到这与Https的目标类似,https协议本身能在未授权的情况下保证客户端发出信息的安全,任何一方在没有合法证书的情况下是不能直接获取请求内容的。采取加密算法对请求参数进行加密的目的不止于此,使用加密的作用要比https协议更多,应用更广,譬如当我们作为客户端使用者,但开发者想要对请求细节进行隐藏从而避免被模仿,此时我们通过Https是能获取到请求参数的,因为请求是由我们这一方发起的,装载证书抓包即可,但如果使用非对称加密,即使我们拥有公钥,也永远无法解密得知实际的请求内容。

    在Java程序中使用加密不难,在此不予举例,通常使用较多的是AES和RSA加密方式,需要注意的是,如果我们要使用AES256加密,需要额外下载jdk中的jar文件并进行替换,默认的jdk并不支持256位的AES加密。可以从以下网址下载:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html,下载会得到一个zip包,将里面的local_policy.jar和US_export_policy.jar解压到JDK安装目录\jre\lib\security下覆盖原文件即可,独立JRE的话也是覆盖相同路径的文件。

数字签名

    数字签名是一种公认的比较好用的防止数据篡改、保证服务数据安全的手段,除去对调用方的校验、还有对请求时间和请求体的全方面验证,最大程度确保了数据的完整性和安全。数字签名也是OpenAPI常用的手端之一,数字签名主要有以下几个要素:

最佳实践

    结合以上几个要素,我们在这里可以设计一个比较通用的数字签名:

    而在服务端,也需要校验以下内容:

当以上都验证通过,此时可以判定这是绝对安全的消息。

附:公私钥的使用

    非对称加密中,一般公钥是可以公开的,私钥是程序内部或后台保密的。这就注定公私钥的使用在加密和数字签名两种场景中使用方式也是不同的,在加密场景下,采用公钥加密,私钥解密的方式,只有服务端可以读取密文原文。但在签名验证中,这一过程恰好是相反的,服务端不希望签名被篡改和模仿,因此私钥往往是用来加密的,用来验证的公钥则公开,采用公钥解密,私钥加密的方式。


扫盲——加密那些事2021-05-14鱼鱼

{{commentTitle}}

评论   ctrl+Enter 发送评论