Python中如何在Flask端点共享公钥实现客户端加密
客户端接收并使用Flask返回的RSA公钥加密数据的实现方案
你已经完成了服务器端公钥分发的核心逻辑,下面针对Python客户端和**JavaScript客户端(浏览器/Node.js)**分别给出具体实现方案,同时补充关键的最佳实践:
一、Python客户端实现
如果客户端同样使用Python,推荐用和服务器一致的cryptography库来处理公钥加载和加密:
步骤与代码示例
import requests from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.backends import default_backend def get_and_use_public_key(): # 1. 从Flask端点获取公钥 response = requests.get("http://your-server-domain/bob_publickey") public_key_pem = response.json()["publickey"].encode("utf-8") # 2. 加载PEM格式的公钥 public_key = serialization.load_pem_public_key( public_key_pem, backend=default_backend() ) # 3. 加密数据(注意:2048位RSA密钥最多加密245字节明文) plaintext = b"需要加密的敏感数据" ciphertext = public_key.encrypt( plaintext, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) # 4. 将加密字节转为Base64字符串(方便HTTP传输) import base64 ciphertext_b64 = base64.b64encode(ciphertext).decode("utf-8") # 后续可将ciphertext_b64发送至服务器 return ciphertext_b64
二、JavaScript客户端实现
1. 浏览器端(使用Web Crypto API)
浏览器原生支持Web Crypto API,无需额外依赖:
async function encryptWithServerPublicKey() { // 1. 获取服务器公钥 const response = await fetch('http://your-server-domain/bob_publickey'); const data = await response.json(); const publicKeyPem = data.publickey; // 2. 将PEM格式公钥转为ArrayBuffer const pemHeader = "-----BEGIN PUBLIC KEY-----"; const pemFooter = "-----END PUBLIC KEY-----"; const publicKeyRaw = publicKeyPem.replace(pemHeader, '').replace(pemFooter, '').replace(/\s/g, ''); const publicKeyBuffer = Uint8Array.from(atob(publicKeyRaw), c => c.charCodeAt(0)); // 3. 导入公钥 const publicKey = await window.crypto.subtle.importKey( "spki", publicKeyBuffer, { name: "RSA-OAEP", hash: "SHA-256" }, false, ["encrypt"] ); // 4. 加密数据(需转为ArrayBuffer) const plaintext = new TextEncoder().encode("需要加密的敏感数据"); const ciphertext = await window.crypto.subtle.encrypt( { name: "RSA-OAEP" }, publicKey, plaintext ); // 5. 转为Base64字符串便于传输 const ciphertextB64 = btoa(String.fromCharCode(...new Uint8Array(ciphertext))); // 发送至服务器 return ciphertextB64; }
2. Node.js端(使用内置crypto模块)
Node.js内置crypto模块可直接处理RSA加密:
const axios = require('axios'); const crypto = require('crypto'); async function encryptData() { // 1. 获取公钥 const response = await axios.get('http://your-server-domain/bob_publickey'); const publicKeyPem = response.data.publickey; // 2. 加密数据 const plaintext = "需要加密的敏感数据"; const ciphertext = crypto.publicEncrypt( { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, Buffer.from(plaintext) ); // 3. 转为Base64字符串 const ciphertextB64 = ciphertext.toString('base64'); // 发送至服务器 return ciphertextB64; }
三、最佳实践
- 强制使用HTTPS:公钥的传输必须通过HTTPS,防止中间人攻击替换公钥,否则加密逻辑完全失效。
- 缓存公钥:客户端无需每次加密都请求公钥,可将获取到的公钥缓存(比如本地存储、内存),仅在密钥轮换时更新。
- 处理加密长度限制:2048位RSA密钥最多只能加密245字节的明文,若需加密大文件/长文本,建议采用对称加密+RSA加密对称密钥的混合方案:
- 客户端生成随机对称密钥(如AES)
- 用对称密钥加密大数据
- 用服务器公钥加密对称密钥
- 将加密后的对称密钥+加密数据一起发送给服务器
- 密钥轮换机制:定期生成新的密钥对,避免长期使用同一密钥,可在服务器端添加版本标识,客户端通过版本判断是否需要更新公钥。
内容的提问来源于stack exchange,提问作者seraf
相关产品推荐
相关产品推荐

