Android 网络全栈攻略(二)—— 编码、加密、哈希、序列化与字符集

Android 网络全栈攻略系列文章:
Android 网络全栈攻略(一)—— HTTP 协议基础
Android 网络全栈攻略(二)—— 编码、加密、哈希、序列化与字符集
Android 网络全栈攻略(三)—— 登录与授权
Android 网络全栈攻略(四)—— TCPIP 协议族与 HTTPS 协议
Android 网络全栈攻略(五)—— 从 OkHttp 配置来看 HTTP 协议
Android 网络全栈攻略(六)—— 从 OkHttp 拦截器来看 HTTP 协议一
Android 网络全栈攻略(七)—— 从 OkHttp 拦截器来看 HTTP 协议二

今天要讲解数据表示与安全处理范畴内的概念:编码、序列化、哈希、加密。它们的核心是如何将信息在不同形式、场景下安全高效地转换与传输,为 HTTPS 加密通信的学习奠定基础。

1、编码

编码是将信息从一种形式或格式转换为另一种形式或格式的过程,目的是为了满足特定的需求,如存储、传输、处理或安全。

下面介绍常用的编码技术。

1.1 Base64

将二进制数据转换成由 64 个字符组成的字符串的编码算法。“二进制数据”从广义上来讲,所有所有计算机数据都是二进制数据(包括文本文档、图片、游戏等),而从狭义上特指非文本数据(更通用),这里我们采用的是狭义理解。

字符组成是英文大小写字母 52 个 + 数字 0 ~ 9 共 10 个 + 特殊符号(+/)共计 64 个:

在这里插入图片描述

编码原理:每三个原始字节(24 位)转换为 4 个 Base64 字符:

在这里插入图片描述

原始字符,三个一组,一共 24 位,每 6 位组成一个 Base64 字符,转换成十进制后查表即可。当原始字符不足三字节时,用 = 补足(只有一个字节补两个 =,有两个字节时补一个 =):

在这里插入图片描述

实际应用中,常用于仅支持文本传输的场景中传递二进制数据。典型场景有早期邮件附件传输(将图片转为 Base64 字符串传输后再解码)、简易聊天软件发送图片、需要文本形式存储二进制数据的场景。

常见误区:

  • 安全性:Base64 是编码而不是加密算法,其码表公开可逆向解码,因此其安全性不高
  • 效率:原本 3 个字节的数据经过 Base64 编码后需要 4 个字节,体积膨胀了 33%,因此效率也低

Base64 有一个变种:Base58,去除易混淆字符(0/O, I/l)、去掉加号和斜杠(方便双击复制),用于比特币地址编码。

现代替代方案:应优先使用原生二进制传输协议。

1.2 字符集

字符集是经过字符编码的结果,字符集就是⼀个由整数向现实世界中的⽂字符号的 Map。常见字符集如下:

  • ASCII:美国信息交换标准代码
    • 诞生时间:1967年
    • 编码范围:7 位二进制(0~127),仅有 128 个字符(包含英文字母、数字、标点符号及控制字符)
    • 特点:
      • 仅支持英语,无法表示其他语言字符
      • 扩展 ASCII(8位,0~255)由厂商自行定义,导致兼容性问题(如 IBM 的扩展字符)
    • 典型场景:早期计算机系统、纯英文文本传输
  • ISO/IEC 8859 系列:对 ASCII 进⾏扩充且完全兼容
    • 诞生时间:1987 年
    • 编码范围:8 位二进制(0~255)
    • 子集示例:ISO-8859-1(Latin-1):西欧语言(如法语、西班牙语)、ISO-8859-5:西里尔字母(俄语等)、ISO-8859-7:希腊语
    • 特点:
      • 每个子集覆盖特定语言区域,但不同子集互不兼容
      • 不支持多语言混合使用(如同时显示中文和法语)
    • 典型场景:早期网页、欧洲本地化软件
  • GB 系列:中文国标字符集,中国⾃研标准,多字节,字符集 + 编码
    • GBK:诞生于 1980 年,采用双字节编码(兼容 ASCII),有 7445 个字符(含 6763 个汉字、682 个符号),是中国大陆首个中文编码标准,不支持繁体字
    • GB2312:诞生于 1995 年,扩展双字节(兼容 GB2312),有 21886个(含繁体字、生僻字),是 Windows 系统默认中文编码
    • GB18030:诞生于 2000 年(最新版 2022 年),变长编码(1/2/4字节,兼容 GBK 和 Unicode),覆盖 Unicode 全部字符(如 Emoji、少数民族文字)。是中国国家标准,强制用于政府、金融等领域
  • Unicode:十几万个字符,多字节,是首次对拉丁语之外的字符进行编码的字符集
    • 诞生时间:1991 年
    • 核心目标:统一全球所有字符的唯一编码(而非编码方式)
    • 编码方式:
      • UTF-8:变长(1 ~ 4 字节),兼容ASCII,互联网首选(占比 98% 以上)
      • UTF-16:定长 2 字节(或 4 字节代理对),Java/C# 默认使用
      • UTF-32:定长 4 字节,空间效率低,用于内部处理
    • 版本演进:
      • Unicode 1.0(1991):覆盖现代语言基本字符
      • Unicode 15.0(2023):支持 149,813 个字符(含 Emoji 14.0)
    • 典型场景:国际化软件、现代操作系统、网页(HTML5 默认 UTF-8)

Unicode 是现代互联网的绝对基石,UTF-8 是目前互联网上占绝对主导地位的字符编码(超过 95% 的网页使用它)。它最大的优点是兼容ASCII(ASCII 字符在 UTF-8 中用一个字节表示,且编码相同),并且是可变长度编码(1 到 4 个字节),对主要使用拉丁字母的文本非常空间高效。它也是许多协议(如 HTTP、XML、JSON)推荐的或默认的编码。

1.3 URL 编码

URL 编码用于在 URL (统一资源定位符) 中对特殊字符和非 ASCII 字符进行编码。将不安全或保留字符(如空格、&, =, %, /, ?, #, 非 ASCII 字符)转换为%后跟两个十六进制数字的形式(如空格变成%20,汉字“中”在 UTF-8 下会被编码为%E4%B8%AD)。这是构建有效 URL 和提交 Web 表单(application/x-www-form-urlencoded)的关键:

  • 转义机制:将 URL 中的保留字符(如正斜杠/)用百分号%进行编码,例如"安卓"被编码为%e5%ae%89%e5%8d%93
  • 目的:消除歧义,避免解析错误
  • 应用场景:浏览器地址栏输入特殊字符时自动转换,如"&“符号在查询参数中需要编码为”%26"
  • 核心作用:消除歧义避免解析错误,例如搜索"隐秘&伟大"时需编码为"隐秘%26伟大"防止被解析为两个参数

1.4 压缩与解压缩

压缩属于编码吗?由于编码就是使用固定规则将数据从 A 格式转换为 B 格式并可逆转换,而压缩算法具备编码的核心特征——可逆的格式转换,因此压缩属于编码。

压缩与解压缩:

  • 定义:通过改变数据存储方式减小空间占用(压缩),再还原为原始格式(解压缩)的过程
  • 典型算法:
    • DEFLATE:ZIP 文件使用的核心压缩算法
    • JPEG:图像压缩标准
    • MP3:音频压缩格式

像 JPEG 与 MP3 都属于“压缩编码”,它们都属于有损编码,不可逆;而 ZIP 属于无损编码。

2、序列化

把数据对象(⼀般是内存中的,例如 JVM 中的对象)转换成字节序列的过程。对象在程序内存⾥的存放形式是散乱的(存放在不同的内存区域、并且由引⽤进⾏连接),通过序列化可以把内存中的对象转换成⼀个字节序列,从⽽使⽤ byte[] 等形式进⾏本地存储或⽹络传输,在需要的时候重新组装(反序列化)来使⽤。

序列化的目的是让内存中的对象可以被储存和传输。

序列化不是不属于编码范畴。编码是把数据由⼀种数据格式转换成另⼀种数据格式;⽽序列化是把数据由内存中的对象(⽽不是某种具体的格式)转换成字节序列。没有发生格式的变化,因此不是编码。

3、哈希

哈希(Hash)的概念如下:

  • 定义:把任意数据转换成指定⼤⼩范围(通常很小,例如 256 字节以内)的数据
  • 作用:相当于从数据中提出摘要信息,因此最主要⽤途是数字指纹
  • 经典算法:Hash 算法两个要求:碰撞率低、不易破解。常用算法有 MD5、SHA1、SHA256 等
  • 实际用途:
    • 唯一性验证:如 Java 中的 hashCode 方法
    • 数据完整性验证:从⽹络上下载⽂件后,通过⽐对⽂件的 Hash 值(例如 MD5、SHA1),可以确认下载的⽂件是否有损坏。如果下载的⽂件 Hash 值和⽂件提供⽅给出的 Hash 值⼀致,则证明下载的⽂件是完好⽆损的
    • 快速查找:HashMap
    • 隐私保护:比如将用户的登录密码取 Hash 值后再网络上传输保护密码安全

下面从 Hash 的实际用途来谈谈 Hash。

Java 判断两个对象相等时会用到 Hash 的唯一性验证做一个初步判断。先通过 hashCode() 拿到两个对象的指纹,如果指纹相等,那么再用 equals() 判断两个对象是否真正相等。这样可以提升判等速度,因为:

  • 两个对象的 hashCode() 返回 int 值,如果该值不相等那么两个对象一定不等。判断两个 int 值要比直接使用 equals() 判断两个对象的各种成员是否相等要快得多
  • 由于哈希算法是有碰撞率的,意味着有可能两个不同的对象 hashCode() 相等,此时再使用 equals() 做精细判断两个对象是否结构性相等。综合考量还是 hashCode() + equals() 比直接使用 equals() 要快

这也是为什么在修改 equals() 时要同步修改 hashCode() 保证相等对象的 hashCode() 必须相等的原因。快速查找的 HashMap 也是类似的原理。

接下来再说说隐私保护。当重要数据必须暴露的时候,有时可以选择暴露它的 Hash 值(例如 MD5),以保障原数据的安全。例如⽹站登录时,可以只保存⽤户密码的 Hash 值,在每次登录验证时只需要将输⼊的密码的 Hash 值和数据库中保存的 Hash 值作⽐对就好,⽹站⽆需知道⽤户的密码。这样,当⽹站数据失窃时,⽤户不会因为⾃⼰的密码被盗导致其他⽹站的安全也受到威胁。现在很少有网站提供密码找回功能了,因为网站也不保存密码本身,而是保存密码的 Hash 值了。

当然,只通过 Hash 值也不是百分百安全的。例如网站在让你设置密码时,通常不允许你设置“弱密码”,时为了防止别有用心的人利用彩虹表(Rainbow Table)破解这些弱密码。

彩虹表是一种预计算的哈希值破解工具,主要用于快速破解通过哈希算法(如 MD5、SHA-1 等)存储的密码。它本质上是“字典攻击的升级版”,但通过特定技术大幅减少了存储空间需求,提高了破解效率。

彩虹表的核心原理如下:

  • 利用哈希函数特性:密码存储时通常用哈希函数(如 sha256(password))生成固定长度的字符串。哈希不可逆(无法直接反推密码),但相同密码的哈希值始终相同
  • 预计算哈希链:彩虹表通过预先生成大量「明文→哈希」的映射链,并仅存储每条链的起点和终点(大幅节省存储空间)
  • 链式碰撞搜索:当需要破解某个哈希值时,通过反复“哈希→明文”的链式推算,尝试找到与目标哈希匹配的链终点,从而回溯出原始明文密码

彩虹表通过以上原理,针对弱密码(简单密码,如 6 位数字、常见单词)的破解效率极高,并且以空间换时间,牺牲存储空间(如几百 GB 到几 TB 的彩虹表)换取快速破解能力,避免了实时暴力穷举的耗时问题。

为了防御彩虹表攻击,可以采取以下措施:

  • 加盐:存储密码时,为每个用户生成随机盐值(Salt),并将 盐值+密码 一起哈希(如 sha256(salt + password))。由于盐值唯一且被各家网站后台严密保管不会泄露,因此彩虹表失效
  • 慢哈希算法:使用计算缓慢的哈希算法(如 PBKDF2、Bcrypt、Argon2),增加暴力破解的时间成本
  • 强制使用强密码:要求用户设置长密码(>12 位)且包含字母、数字、符号的混合组合

Hash 不是编码也不是加密,因为 Hash 是单向过程,往往是不可逆的,⽆法进⾏逆向恢复操作,故而既不是编码也不是加密。

MD5 不是加密!!!

4、加密

现代密码学可以加密任何⼆进制数据,通常有两种加密方式:对称加密与非对称加密。

4.1 对称加密

对称加密要点:

  • 原理:通信双⽅使⽤同⼀个密钥,使⽤加密算法配合上密钥来加密,解密时使⽤加密过程的完全逆过程配合密钥来进⾏解密
  • 常用算法:DES(56 位密钥,密钥太短⽽逐渐被弃⽤)、AES(128 位、192 位、256 位密钥, 现在流⾏)
  • 缺点:不能在不安全⽹络上传输密钥,⼀旦密钥泄露则加密通信失败
  • 破解:
    • 破解思路:拿到⼀组或多组原⽂-密⽂对,设法找到⼀个密钥,这个密钥可以将这些原⽂-密⽂对中的原⽂加密为密⽂,以及将密⽂解密为原⽂的组合,即为成功破解
    • 反破解:⼀种优秀的对称加密算法的标准是,让破解者找不到⽐穷举法(暴⼒破解法)更有效的破解⼿段,并且穷举法的破解时间⾜够⻓(例如数千年)

对称加密示意图如下:

请添加图片描述

对称加密的问题就在于密钥一定是要通过网络传到对端,这样对端才能通过密钥解密。但网络具有不安全性(如果安全就不用加密了),一旦密钥被窃取,那么加密算法就会被破解,数据安全也就无从谈起了。

4.2 非对称加密

非对称加密要点:

  • 原理:使⽤公钥对数据进⾏加密得到密⽂;使⽤私钥对数据进⾏解密得到原数据
  • 延伸用途:数字签名
  • 常用算法:
    • RSA:公钥通常固定或可预测、同一系统中多个用户的公钥可能相同、支持加密和签名双重功能
    • DSA:不具备加密功能,只有签名功能。专为签名优化,验证速度更快
  • 优缺点:可以在不安全⽹络上传输密钥(公钥),但计算复杂,因此性能相⽐对称加密差很多

非对称加密示意图,使用相同的加密算法,加密用公钥,解密用私钥:

请添加图片描述

通信双方在生成各自的公钥与私钥后,将公钥发送给对方,这样对方可以用公钥加密数据,自己接收到后用私钥解密:

请添加图片描述

这样公钥不怕在网络上被截获,因为截获者没有私钥无法解密,可以有效防止中间人攻击,这样就解决了对称加密的密钥传输安全问题。

数字签名

非对称加密具有双向可解性。意思是说,非对称加密中公钥和私钥可以互相解密对方加密的数据。用私钥加密的数据只能用对应的公钥解密,反之亦然。

但需要注意密钥的角色是固定的。虽然密钥可以互解,但公钥和私钥的角色不能互换。例如椭圆曲线算法中公钥是通过私钥计算得出,若将私钥公开,那么公钥就可以通过算法计算出来(但是无法通过公钥倒推计算出私钥),导致安全漏洞。

利用双向可解性,非对称加密可以延伸一下用途,就是数字签名:

请添加图片描述

大致过程:

  • A 端将原数据的摘要利用加密算法配合私钥加密为签名数据的过程称为签名
  • B 端使用同样的加密算法配合公钥解密,对原数据的摘要进行比对的过程称为验证

为了方便的查看原数据,通常会把原数据附加到签名数据上。因为签名后的数据是没有意义的二进制,无法直接查看原数据的内容(只能在验证后才能看到真容),比如原数据如果是文本的话,把原数据带上可以方便 B 端查看文本内容。

前面说到,使用非对称加密可以让第三方在截获消息的情况下,因为没有私钥而无法解密读取消息。但第三方还可以做另一种攻击 —— 消息伪造。第三方可以用截获的公钥加密伪造的消息然后发给私钥持有者,由于私钥持有方无法验证消息到底来自于哪一方,因此它可能会误信中间人攻击发出的伪造信息。此时可以使用数字签名,保证你收到的消息不是中间人伪造的消息,示意图如下:

在这里插入图片描述

上半部分使用对方公钥加密数据,保证第三方无法看懂密文;下半部分使用自己的私钥进行签名,保证第三方无法伪造消息。当然,由于这只是一个示意图,因此你能看出这过程有一个明显漏洞,就是第三方可以通过截获公钥还原签名数据。这是因为我们这个图只是想说明需要用加密与签名两种方式来预防中间人攻击。完整的签名与验证示意图如下:

请添加图片描述

步骤描述:

  • 对原数据做 hash 运算提取出摘要(或者叫指纹)
  • 通过加密算法使用私钥对摘要签名,得到签名后的摘要,附加在原数据的后面。这个签名后的摘要数据很小,不会对签名后的数据的体积有很大影响。而且即便第三方截获公钥对签名解密,得到的也只是原数据的摘要,而不是原数据本身
  • 通过相同的加密算法使用公钥验证(解密),得到一个待验证的摘要
  • 对传输过来的原数据做一次 hash 得到摘要,与待验证的摘要比对一致性,如果一致,说明签名是合法的(即确实是通信的对端,而不是第三方发来的信息)

破解思路

对非对称加密(如 RSA、ECDSA)的破解思路:

  • 和对称加密不同之处在于,⾮对称加密的公钥很容易获得,因此制造原⽂-密⽂对是没有困难的事
  • 所以,⾮对称加密的关键只在于,如何找到⼀个正确的私钥,可以解密所有经过公钥加密过的密⽂。找到这样的私钥即为成功破解
  • 由于⾮对称加密的⾃身特性,怎样通过公钥来推断出私钥通常是⼀种思路(例如 RSA),但往往最佳⼿段依然是穷举法,只是和对称加密破解的区别在于,对称加密破解是不断尝试⾃⼰的新密钥是否可以将⾃⼰拿到的原⽂-密⽂对进⾏加密和解密,⽽⾮对称加密时不断尝试⾃⼰的新私钥是否和公钥互相可解
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值