Session、Cookie、Token和 LocalStorage 的区别
在 Web 开发中,管理用户状态是至关重要的。HTTP 协议的无状态性意味着每个请求都是独立的,服务器不会记住客户端的上一次请求。为了克服这个问题,我们需要一些机制来维持用户的状态,例如在用户登录场景中。这就是 session、cookie 和 token 发挥作用的地方。
Cookie
Cookie 是一种在客户端存储数据的技术。服务器发送一个小的文本文件(cookie)到客户端的浏览器,浏览器将其存储起来。当客户端再次发送请求时,浏览器会自动将相应的 cookie 信息附加到请求头中,服务器通过这些信息来识别客户端。
Cookie 的特点
- 存储限制:大小通常限制在 4KB 左右。
- 自动携带:浏览器每次请求都会自动携带 cookie。
- 安全性问题:数据可以被查看,但可以通过设置 HttpOnly 和 Secure 标志来提高安全性。
- 存储限制:仅支持字符串数据。
- 生命周期:可以设置过期时间,如果没有设置,则浏览器关闭后失效。
Cookie 的使用
- 用户识别:存储用户ID或偏好设置。
- 购物车信息:存储用户的购物车内容。
Session
Session 是一种服务器端的状态管理技术。当客户端发送请求时,服务器会检查请求中是否包含一个唯一的标识符(sessionId)。如果找到,服务器会根据这个标识符查找对应的 session 数据。如果没有找到,服务器会创建一个新的 session 并生成一个新的 sessionId。
Session 的特点
- 安全性:存储在服务器端,比 cookie 更安全。
- 数据类型:可以存储任意类型的数据。
- 有效期:通常较短,需要定期更新。
- 存储空间:比 cookie 大,理论上只受服务器内存限制。
- 传输方式:通常依赖于 Cookie 来传递一个唯一的 Session ID,服务器通过这个 ID 来识别用户。
Session 的使用
- 用户登录状态:存储用户的登录信息。
- 临时数据:存储用户在会话期间的临时数据。
Token
Token 是一种在客户端和服务端之间传递身份信息的机制。当用户登录成功后,服务端生成一个 token 并发送给客户端。客户端在后续的请求中携带这个 token,服务端通过验证 token 的合法性来识别用户。
Token 的特点
- 无状态:服务端不需要存储 token,有助于构建无状态的客户端-服务器架构。
- 安全性:可以有效防止 CSRF 攻击。
- 灵活性:可以用于多种认证机制,如 JWT(JSON Web Tokens)。
- 传输方式:通常在 HTTP 请求的 Header 中传输,不依赖于 Cookie。
Token 的使用
- 认证:用户登录后生成 token,用于后续请求的身份验证。
- 授权:根据 token 中的信息,决定用户是否有权限执行特定操作。
LocalStorage
- 存储位置:LocalStorage 数据存储在客户端。
- 生命周期:除非被手动清除,否则数据将永久保存。
- 安全性:安全性较低,任何人都可以读取存储的信息,不适合存储敏感数据。
- 传输方式:不会随着每个 HTTP 请求发送,仅在客户端脚本中可以访问。
布隆过滤器
在处理大规模数据集时,快速且准确地判断一个元素是否属于某集合是一个常见且具有挑战性的问题。布隆过滤器(Bloom Filter)提供了一种高效且节省空间的解决方案。本教程将带您深入了解布隆过滤器的原理、操作和应用。
核心概念
位数组(Bit Array)
布隆过滤器的核心是一个位数组,通常初始化为全0。每个位代表一个元素的存在性,0表示不存在,1表示存在或可能存在。
哈希函数(Hash Functions)
布隆过滤器使用多个独立的哈希函数,每个函数都能将输入元素映射到位数组的特定位置。这些函数应具备均匀分布的特性,以确保高效和准确性。
操作原理
添加元素
- 使用哈希函数将元素映射到位数组的多个位置。
- 将这些位置上的位设置为1。
查询元素
- 使用相同的哈希函数将元素映射到位数组的相应位置。
- 检查这些位置的位是否都为1。如果有任何位为0,则元素肯定不存在。如果都为1,则元素可能存在。
优缺点分析
优点
- 节约内存:相比哈希表,布隆过滤器占用更少的空间,因为它不存储元素本身,只存储哈希值。
- 高效查询:布隆过滤器的查询操作具有常数时间复杂度(O(1)),无需遍历整个集合。
缺点
- 误判率:布隆过滤器可能错误地报告元素存在,但不会错误地报告元素不存在。
- 不支持删除:传统布隆过滤器不支持删除操作,因为这会提高误判率。
删除操作
传统布隆过滤器不支持删除操作。但如果需要这一功能,可以通过在每个位上使用计数器来实现。这样,每个位不再只存储0或1,而是存储该位置上的元素数量。这种方法会增加空间复杂度,但允许删除操作。
跨域资源共享(CORS)
在Web开发中,跨域资源共享(CORS)是一个经常遇到的问题。
同源策略
浏览器出于安全考虑,实施了同源策略(Same-origin policy),用于限制一个网页对另一个网页的访问权限,以防止数据被非法获取。这意味着,默认情况下,浏览器只允许请求与当前页面相同协议、域名和端口的资源。这一策略防止了恶意网站访问其他网站的数据,但同时也限制了合法的跨域请求。
同源策略的影响范围:
- JavaScript访问限制:一个网页中的JavaScript只能读取或修改来自同一源的文档和资源。
- XMLHttpRequest限制:跨源HTTP请求也受到限制,不过现代浏览器通过CORS(跨源资源共享)机制允许服务器明确许可跨源请求。
- Web Storage访问限制:如localStorage和sessionStorage只允许同源访问。
跨域问题的产生
当我们尝试从不同的源(协议、域名或端口)请求资源时,就会遇到跨域问题。例如,如果我们的前端应用部署在http://cengxuyuan.cn
,而尝试请求http://cengxuyuan.com
的数据,就会触发浏览器的同源策略限制。
CORS解决方案
CORS是一种机制,允许服务器指定哪些源可以访问其资源。这通过设置HTTP头部信息实现。
前端代理解决跨域
在前端,我们可以使用代理服务器来绕过同源策略。例如,在Vue.js中,我们可以在vue.config.js
中设置代理:
查看代码
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://cengxuyuan.cn',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
这样,当我们在应用中请求/api/data
时,实际上请求的是http://cengxuyuan.cn/data
,但浏览器认为这是同源请求。
后端解决跨域
后端解决跨域通常有几种方法:
全局CORS配置:在Spring Boot应用中,我们可以添加一个全局CORS配置类:
查看代码
java@Configuration public class GlobalCorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .exposedHeaders("*"); } }; } }
使用过滤器:我们也可以创建一个过滤器来设置CORS头部信息:
查看代码
java@Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); response.setHeader("Access-Control-Allow-Headers", "Content-Type"); chain.doFilter(req, res); } }
使用注解:在方法或类上使用
@CrossOrigin
注解:java@RestController public class MyController { @CrossOrigin @GetMapping("/data") public ResponseEntity<?> getData() { // ... } }
JSONP
当然,除了CORS之外,还有一些其他的解决方案可以处理跨域问题。
JSONP(JSON with Padding)是一种利用<script>
标签无跨域限制的漏洞来发送跨域请求的方法。它只支持GET请求。
原理:通过动态创建<script>
标签,向服务器发送请求,服务器返回一个包装了数据的函数调用(通常是回调函数)。
示例:
function handleData(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'http://cengxuyuan.cn/data?callback=handleData';
document.body.appendChild(script);
优点:兼容性好,可以用于老版本的浏览器。
缺点:只支持GET请求;安全性较差,容易受到XSS攻击。
代理服务器
除了前端代理,我们还可以使用专门的代理服务器(如Nginx)来处理跨域请求。
示例:在Nginx配置中添加代理设置,添加 CORS 相关的 HTTP 头部,允许跨域请求:
location /api/ {
proxy_pass http://api.example.com/;
add_header 'Access-Control-Allow-Origin' '*';
}
或者前端应用和代理服务器都部署在同一域名下,这样前端应用就可以通过调用代理服务器提供的API来发送跨域请求,而不会触发浏览器的同源策略限制。这种方法通常用于内部应用或者当后端 API 不支持 CORS 时。
优点:配置简单,可以处理复杂场景。
缺点:需要额外的服务器配置。
WebSockets
WebSockets是一种全双工通信协议,不受同源策略限制。
示例:
const socket = new WebSocket('ws://api.example.com/socket');
socket.onopen = function(event) {
socket.send('Hello Server!');
};
socket.onmessage = function(event) {
console.log('Client received a message',event);
};
优点:实时通信,适合需要频繁交互的应用。
缺点:需要服务器支持WebSocket协议。
加密算法
加密算法是信息安全领域中非常重要的组成部分,它们用于保护数据的机密性、完整性和可用性。加密的基本思想是将原始信息(明文)转换为不可读的形式(密文),只有拥有正确解密密钥的人才能将其恢复为原始形式。
加密算法主要分为两大类:对称加密和非对称加密。如果不考虑解密,还有哈希算法。
对称加密
对称加密算法使用相同的密钥进行加密和解密。这意味着如果某人能够加密一条消息,那么只要他们拥有相同的密钥,就能解密这条消息。对称加密算法通常比非对称加密算法更快,更适合处理大量数据。
常见的对称加密算法
DES (Data Encryption Standard)
- 安全性:DES是早期广泛使用的对称密钥算法,采用56位的密钥。但随着计算能力的提升,DES的安全性已不足以抵御现代化的攻击手段,尤其是暴力破解法。
- 速度和应用:DES在处理大量数据时表现出色,这归功于其较快的加密处理速度。然而,由于安全性问题,现代应用中DES已逐渐被更高级别的加密算法所替代。
3DES (Triple DES)
- 增强的安全性:3DES通过应用三把独立的56位密钥,进行了三轮DES加密,极大地增强了加密强度,总密钥长度达到168位。
- 性能考量:尽管3DES提供了比DES更好的安全性,但其加密和解密的速度较慢,因此在需要处理大量数据的应用中可能不是最佳选择。
AES (Advanced Encryption Standard)
- 高安全性:AES是目前最常用的对称加密算法之一,支持128位、192位和256位长度的密钥。它不仅提供了高级别的安全性,也成为了多种系统和设备的标准加密协议。
- 广泛应用:由于其安全性和处理性能的平衡,AES被广泛应用于各种安全敏感的领域,如金融、通信和数据存储等。
RC4 (Rivest Cipher 4)
- 流密码特性:RC4是一种流密码算法,它采用可变长度的密钥对数据进行加密和解密,曾因其简单和高效而广受欢迎。
- 安全和更新:尽管RC4在多个领域有广泛应用,但近年来发现了多个安全漏洞,导致许多系统推荐停止使用RC4,转而采用更安全的算法如AES。
Blowfish
- 变长密钥:Blowfish采用变长密钥,并以其高效的性能和安全性著称。Blowfish的设计旨在替代已有的老旧算法,提供更高级别的安全性。
- 适应性强:Blowfish适用于多种平台和系统,尤其在需要高安全性和较好性能的情况下,是一个合适的选择。
非对称加密
非对称加密(Asymmetric Encryption),也称为公钥加密(Public Key Encryption),它使用两个不同的密钥:一个公钥(Public Key)和一个私钥(Private Key)。
这两个密钥是数学相关的,但它们并不相同,且不能从一个密钥推导出另一个密钥。
非对称加密的核心思想是,公钥用于加密数据,而私钥用于解密。公钥可以公开分享,但私钥必须保密。
非对称加密的基本原理
- 公钥和私钥的生成:非对称加密算法首先生成一对密钥:公钥和私钥。公钥可以公开分享,而私钥必须保密。
- 加密:发送方使用接收方的公钥来加密消息。加密后的消息(密文)只能用接收方的私钥解密。
- 解密:接收方使用自己的私钥来解密发送方加密的消息,恢复原始的明文。
常见的非对称加密算法
非对称加密算法利用了一对数学相关但不能轻易从一个推导出另一个的密钥:公钥和私钥。下面我将详细介绍几种主要的非对称加密算法及其背后的数学原理:
RSA (Rivest-Shamir-Adleman)
RSA 是最著名的非对称加密算法之一,它基于一个数论事实,即将两个大素数相乘容易,但对其进行因式分解却极其困难。
目前没有已知的高效算法可以在合理时间内分解一个足够大的随机产生的合数
其基本原理涉及以下几个步骤:
密钥生成:
- 选择两个大的素数
和 。 - 计算
, 将作为公钥和私钥的一部分。 - 计算欧拉函数
。 - 选择一个整数
,使得 并且 与 互质(没有共同因子)。 - 找到一个整数
,使得 。这可以通过扩展欧几里得算法找到。 - 公钥为
,私钥为 。
- 选择两个大的素数
加密:
- 对明文
(转换成整数),使用公钥 进行加密: 。
- 对明文
解密:
- 使用私钥
解密密文 : 。
- 使用私钥
Diffie-Hellman (DH)
DH 算法用于密钥交换,而不是直接加密消息。它基于离散对数问题的难度。
DH 的安全性基于离散对数问题的难度,即给定
公共参数:
- 选择一个大素数
和一个小的原根 。 - 这些值
和 是公共的。
- 选择一个大素数
密钥生成:
- Alice 选择一个随机数
并计算 。 - Bob 选择一个随机数
并计算 。 - Alice 和 Bob 分别发送
和 给对方。
- Alice 选择一个随机数
共享密钥:
- Alice 计算
。 - Bob 计算
。
- Alice 计算
由于
Elliptic Curve Cryptography (ECC)
ECC 基于椭圆曲线上的离散对数问题。它使用较小的密钥长度来达到与 RSA 或 DH 类似的安全性水平。
ECC 的安全性基于椭圆曲线离散对数问题的难度,即给定椭圆曲线上两点
密钥生成:
- 选择一条椭圆曲线
和一个椭圆曲线上的点 (生成元)。 - 私钥
是一个随机选取的大整数。 - 公钥
通过 计算得到。
- 选择一条椭圆曲线
加密:
- 对明文
选择一个随机点 ,计算 和 。 - 发送密文
。
- 对明文
解密:
- 接收方计算
。
- 接收方计算
DSA (Digital Signature Algorithm)
DSA 是一种用于生成数字签名的算法,它基于离散对数问题。
密钥生成:
- 选择一个大素数
和一个素数 使得 。 - 选择一个整数
使得 。 - 私钥
是一个随机选取的小于 的整数。 - 公钥
通过 计算得到。
- 选择一个大素数
签名:
- 对消息
生成哈希值 。 - 选择一个随机数
计算 。 - 计算
。 - 签名是
。
- 对消息
验证:
- 对消息
重新计算哈希值 。 - 计算
。 - 计算
和 。 - 计算
。 - 如果
,则签名有效。
- 对消息
ECDSA (Elliptic Curve Digital Signature Algorithm)
ECDSA 是基于椭圆曲线的数字签名算法,类似于 DSA,但使用椭圆曲线数学。
密钥生成:
- 选择一条椭圆曲线
和一个椭圆曲线上的点 (生成元)。 - 私钥
是一个随机选取的大整数。 - 公钥
通过 计算得到。
- 选择一条椭圆曲线
签名:
- 对消息
生成哈希值 。 - 选择一个随机数
计算 。 - 计算
和 。 - 签名是
。
- 对消息
验证:
- 对消息
重新计算哈希值 。 - 计算
。 - 计算
和 。 - 计算
。 - 如果
,则签名有效。
- 对消息
JWT
JWT(JSON Web Token)是一种在网络应用环境间安全地传输信息的一种基于JSON的开放标准(RFC 7519)。
它可以在各方之间以JSON对象的形式安全地传输信息,因为它是经过数字签名的,所以可以被验证和信任。
JWT的组成
一个JWT由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature),它们之间用点(.
)分隔。
头部(Header)
- 描述JWT的基本信息,例如类型(JWT)和所使用的签名算法(如HMAC SHA256或RSA)。
- 头部的JSON格式如下:json
{ "alg": "HS256", "typ": "JWT" }
- 然后将这个JSON字符串进行Base64Url编码,形成JWT的第一部分。
载荷(Payload)
- 包含了声明(Claims),声明是关于实体(通常是用户)和其他数据的声明(如过期时间、签发者等)以及自定义声明。
- 载荷的JSON格式可能如下:json
{ "sub": "1234567890", "name": "John Doe", "admin": true }
- 载荷也经过Base64Url编码,形成JWT的第二部分。
签名(Signature)
- 签名用于验证消息在整个过程中没有被更改,并且对于使用私钥签名的JWT,它还可以验证JWT的发送者。
- 创建签名的方法是,将编码后的头部、载荷、秘钥以及指定的算法(在头部中指定)一起计算得到。
- 签名的公式是:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
- 签名用于验证消息的发送者,并确保在传输过程中消息不被更改。
JWT的工作流程
1. 用户认证
- 用户登录:用户通过用户名和密码或其他认证方式(如OAuth 2.0)向认证服务器发起登录请求。
- 验证身份:认证服务器验证提供的凭据,如果凭据有效,则用户身份得到验证。
2. 生成JWT
- 创建JWT:一旦用户身份得到验证,认证服务器会创建一个JWT。JWT包含以下部分:
- 头部(Header):包含JWT的类型(通常是"JWT")和所使用的签名算法(如HS256)。
- 载荷(Payload):包含声明,这些声明是关于用户和其他数据的声明。常见的声明包括用户ID、用户名、角色、权限等。
- 签名(Signature):使用头部中指定的算法,结合一个秘钥(只有服务器知道),对头部和载荷进行签名。
- 编码JWT:将头部和载荷分别进行Base64Url编码,然后将它们与签名组合起来,形成完整的JWT字符串。
3. 发送JWT给客户端
- 响应:认证服务器将生成的JWT发送给客户端,通常是通过HTTP响应体或者设置在HTTP头部中的一个Cookie。
4. 客户端存储JWT
- 存储JWT:客户端收到JWT后,通常会将其存储在本地,如Cookie、LocalStorage或SessionStorage。
5. 使用JWT进行请求
- 附加JWT:客户端在后续的请求中,通常会通过以下方式将JWT附加到请求中:
- Authorization头部:在HTTP请求的Authorization头部中添加
Bearer <token>
。 - Cookie:如果JWT存储在Cookie中,浏览器会自动将Cookie包含在请求中。
- Authorization头部:在HTTP请求的Authorization头部中添加
6. 服务器验证JWT
- 接收请求:服务器接收到带有JWT的请求。
- 验证签名:服务器使用秘钥和头部指定的算法验证JWT的签名,以确保它是由认证服务器签发的,并且在传输过程中未被篡改。
- 验证声明:服务器验证JWT中的声明,例如检查是否已过期(exp),是否由受信任的发行者(iss)签发,以及是否有正确的受众(aud)。
- 授权:如果JWT验证通过,服务器将授权用户进行请求的资源访问。
7. 响应请求
- 处理请求:服务器处理请求,并根据JWT中的声明提供相应的资源或服务。
- 返回响应:服务器将处理结果返回给客户端。
8. JWT刷新或续签
- 刷新JWT:由于JWT具有过期时间,当JWT接近过期时,客户端可能需要通过发起刷新令牌的请求来获取新的JWT。
- 续签JWT:在某些情况下,服务器可能会允许在JWT过期前续签,以避免用户重新登录。
JWT的优点
- 跨语言:因为是基于JSON的,所以JWT天然具有跨语言支持。
- 紧凑:因为JWT是经过压缩和加密的,所以比较小,适合在HTML和HTTP环境中传输。
- 自包含:载荷中可以包含用户的所有相关信息,避免了多次查询数据库。
- 信任:签名使得接收方可以信任JWT的发送者。只有拥有正确密钥的一方才能生成有效的签名,这通常意味着发送者是可信的。
- 无状态:由于JWT是自包含的,且签名验证不需要服务器保存状态信息,因此JWT可以在分布式系统中无状态地使用,这有助于系统的扩展性和可靠性。
JWT的缺点
- 一旦发布,无法吊销:由于没有集中的存储,一旦签发了JWT,在它过期之前无法吊销。
- 安全性依赖于密钥的保密性:如果密钥泄露,那么签名就可以被伪造。
Base64编码
Base64编码是一种编码方法,用于将二进制数据转换成ASCII字符序列,这样就可以在只支持文本的环境中安全地传输数据。Base64编码常用于在HTTP协议中嵌入图片、传输电子邮件附件以及在Web页面中嵌入小型的二进制数据。
Base64编码的原理
Base64编码的基本原理是将每3个字节(共24位)的二进制数据划分为4组,每组6位,然后将这4组6位二进制数转换成对应的4个十进制数。每个十进制数对应Base64索引表中的一个字符。
- 分组:将待编码的二进制数据分为每组3个字节,即24位。
- 切分:将每组24位二进制数切分为4组,每组6位。
- 转换:将每组6位二进制数转换成十进制数,范围是0到63。
- 查表:根据Base64索引表,将每个十进制数映射到对应的Base64字符。
Base64索引表如下:
查看代码
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Base64编码的步骤
以下是将二进制数据编码为Base64的步骤:
- 将二进制数据分组:将二进制数据每3个字节为一组,不足3个字节时,需要进行填充。
- 将每组3个字节转换为4个6位的组:每组的24位二进制数被划分为4个6位的组。
- 将每个6位的组转换为十进制数:每个6位的组可以表示一个0到63的十进制数。
- 根据Base64索引表映射字符:使用上表将每个十进制数映射到对应的Base64字符。
- 处理填充:如果原始数据的长度不是3的倍数,则在编码后的字符串末尾添加一个或两个
=
字符,以表示填充的字节。
示例
假设我们有以下二进制数据:
Binary: 01001001 01010000 01010100
进行Base64编码的步骤如下:
- 分组:将二进制数据分为一组(这里只有一组)。
- 切分:将这组二进制数据切分为4组,每组6位。
010010 010100 000101 010000
- 转换:将每组6位二进制数转换为十进制数。
010010 -> 18 -> S 010100 -> 20 -> U 000101 -> 5 -> F 010000 -> 16 -> Q
- 查表:根据Base64索引表,将每个十进制数映射到对应的Base64字符。因此,上述二进制数据经过Base64编码后得到的字符串是
01001001 01010000 01010100 -> SUFQ
SUFQ
。
如果原始数据长度不是3的倍数,例如只有两个字节,则会在编码后的字符串末尾添加一个=
字符。如果有更多填充字节,则可能添加两个=
字符。
Base64编码是一种非常常见的数据编码方法,广泛应用于多种场景,尤其是在需要将二进制数据嵌入到文本格式的场合。但是Base64编码并不是为了数据安全设计的,它本身不提供数据保护功能,不应被误用作加密手段。虽然Base64编码并非加密方法,但它能够在一定程度上隐藏原始数据,提供基本的隐秘性。
Base64Url编码
Base64Url编码是Base64编码的一种变体,专为在URL中安全地嵌入二进制数据而设计。在标准的Base64编码中,使用了+
和/
字符,这两个字符在URL中有特殊含义(+
表示空格,/
是路径分隔符),因此不适合直接用在URL中。Base64Url编码通过替换这些字符来避免URL解析错误。
Base64Url编码对Base64编码进行了以下修改:
- 替换
+
为-
:在Base64编码中,+
字符被替换为-
。 - 替换
/
为_
:在Base64编码中,/
字符被替换为_
。 - 去掉填充的
=
字符:在Base64Url编码中,末尾的=
填充字符被去掉。由于URL不关心数据的具体长度,因此可以省略填充字符。
Base64Url编码的步骤
以下是Base64Url编码的具体步骤:
- 对数据进行Base64编码:首先,按照Base64的规则对数据进行编码。
- 替换
+
和/
:将Base64编码结果中的所有+
字符替换为-
,所有/
字符替换为_
。 - 去掉
=
:从编码结果的末尾去掉所有=
字符。
示例
假设我们有以下二进制数据:
Binary: 01001001 01010000 01010100
进行Base64编码后,我们得到:
Base64: QWFCUw==
进行Base64Url编码后,我们得到:
Base64Url: QWFCUw
在这个例子中,我们替换了+
和/
(这里没有出现+
和/
,所以没有替换操作),并且去掉了末尾的=
字符。
注意事项
- URL安全性:Base64Url编码确保编码后的字符串可以安全地嵌入到URL中,不会引起解析错误。
- 数据完整性:由于去掉了填充字符
=
,Base64Url编码后的数据长度可能会不是4的倍数。因此,解码时需要知道原始数据的长度,或者使用其他方式来确保数据的完整性。