Django注册视图解密加密Payload时出现Incorrect padding错误求助
解决Django注册接口AES解密的"Incorrect padding"错误
错误信息
Error at /register/
Incorrect padding
完整Traceback
Environment: Request Method: POST Request URL: http://localhost:8003/register/ Django Version: 4.2 Python Version: 3.9.12 Installed Applications: ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'authentication', 'rest_framework', 'rest_framework_simplejwt.token_blacklist', 'corsheaders'] Installed Middleware: ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware'] Traceback (most recent call last): File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view return view_func(*args, **kwargs) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/django/views/generic/base.py", line 104, in view return self.dispatch(request, *args, **kwargs) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch response = self.handle_exception(exc) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception raise exc File "/home/dubsy/virtualenvs/djangoproject/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch response = handler(request, *args, **kwargs) File "/home/dubsy/virtualenvs/djangoproject/digirepo2/authentication/views.py", line 86, in post cipher = AES.new(base64.b64decode(encryption_secret_key), AES.MODE_ECB) File "/home/dubsy/anaconda3/lib/python3.9/base64.py", line 87, in b64decode return binascii.a2b_base64(s) Exception Type: Error at /register/ Exception Value: Incorrect padding
问题代码片段
前端React代码
import React, { useState } from "react"; import axios from "axios"; import CryptoJS from "crypto-js"; function Signup() { const [focusedInput, setFocusedInput] = useState(""); const [formData, setFormData] = useState({ email: "", first_name: "", last_name: "", password: "", password2: "", }); const handleChange = (e) => { setFormData({ ...formData, [e.target.name]: e.target.value, }); }; const handleSubmit = (e) => { e.preventDefault(); const encryptionSecretKey = "t42uM-crGNqn9tugFvY0IkV6tdKk4RbWbREflNaZ8QA="; const encryptedPassword = CryptoJS.AES.encrypt( formData.password, encryptionSecretKey ).toString(); const encryptedPassword2 = CryptoJS.AES.encrypt( formData.password2, encryptionSecretKey ).toString(); const encryptedEmail = CryptoJS.AES.encrypt( formData.email, encryptionSecretKey ).toString(); const encryptedPayload = { ...formData, password: encryptedPassword, password2: encryptedPassword2, email: encryptedEmail, }; // Send the encrypted payload to the backend axios .post("http://127.0.0.1:8003/register/", JSON.stringify(encryptedPayload)) .then((response) => { // Handle successful response console.log(response.data); }) .catch((error) => { // Handle error console.error(error); }); }; }
后端Django视图代码
class CreateUser(APIView): permission_classes = [AllowAny] def post(self, request): encrypted_payload = request.data.get('encryptedPayload') encryption_secret_key = "t42uM-crGNqn9tugFvY0IkV6tdKk4RbWbREflNaZ8QA=" cipher = AES.new(base64.b64decode(encryption_secret_key), AES.MODE_ECB) decrypted_payload = cipher.decrypt( base64.b64decode(encrypted_payload)).decode().rstrip('\0') decrypted_data = json.loads(decrypted_payload) serializer = UserSerializer(data=decrypted_data) if serializer.is_valid(raise_exception=True): user = serializer.save() // Modify the user attributes as needed user.email = user.email.lower() user.username = user.email.lower() if user.email else None user.first_name = user.first_name.lower() if user.first_name else None user.last_name = user.last_name.lower() if user.last_name else None user.avatar = user.avatar if user.avatar else None if user.first_name and user.last_name: random_string = generate_random_string() slug = slugify( f"{user.first_name} {user.last_name} {random_string}") while User.objects.filter(slug=slug).exists(): random_string = generate_random_string() slug = slugify( f"{user.first_name} {user.last_name} {random_string}" ) user.slug = slug user.set_password(decrypted_data["password"]) user.password2 = None user.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
问题根源及解决步骤
核心问题
- 前后端加密逻辑不匹配:前端单独加密每个字段,后端却期望接收一个名为
encryptedPayload的完整加密 payload,两者完全不对接。 - 密钥处理不一致:CryptoJS默认会对传入的密钥做SHA-256哈希处理后再作为AES密钥,而后端直接解码base64密钥,导致两边密钥实际不同。
- 请求格式错误:前端用
JSON.stringify包裹数据后发送,axios会自动将其转为JSON格式,后端request.data拿到的是解析后的JSON对象,而非加密字符串;同时前端根本没传encryptedPayload字段。
修正方案
1. 前端代码修正
改为加密整个表单对象,明确指定加密模式和填充方式,和后端对齐:
const handleSubmit = (e) => { e.preventDefault(); const encryptionSecretKey = "t42uM-crGNqn9tugFvY0IkV6tdKk4RbWbREflNaZ8QA="; // 先将表单数据转为JSON字符串 const payloadStr = JSON.stringify(formData); // 用CryptoJS加密整个payload,指定模式和填充 const encryptedPayload = CryptoJS.AES.encrypt( payloadStr, CryptoJS.enc.Base64.parse(encryptionSecretKey), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 } ).toString(); // 发送加密后的payload,字段名和后端对应 axios .post("http://127.0.0.1:8003/register/", { encryptedPayload }) .then((response) => { console.log(response.data); }) .catch((error) => { console.error(error); }); };
2. 后端代码修正
对齐加密模式和填充,正确解析CryptoJS的加密结果:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 import json class CreateUser(APIView): permission_classes = [AllowAny] def post(self, request): encrypted_payload = request.data.get('encryptedPayload') if not encrypted_payload: return Response({"error": "Missing encrypted payload"}, status=status.HTTP_400_BAD_REQUEST) encryption_secret_key = "t42uM-crGNqn9tugFvY0IkV6tdKk4RbWbREflNaZ8QA=" # 解码base64密钥 key = base64.b64decode(encryption_secret_key) # 创建AES实例,指定ECB模式和Pkcs7填充 cipher = AES.new(key, AES.MODE_ECB) try: # 解密:先解码base64,再解密,最后去除填充 decrypted_bytes = cipher.decrypt(base64.b64decode(encrypted_payload)) decrypted_payload = unpad(decrypted_bytes, AES.block_size).decode('utf-8') decrypted_data = json.loads(decrypted_payload) except Exception as e: return Response({"error": f"Decryption failed: {str(e)}"}, status=status.HTTP_400_BAD_REQUEST) serializer = UserSerializer(data=decrypted_data) if serializer.is_valid(raise_exception=True): user = serializer.save() # 后续用户处理逻辑不变 user.email = user.email.lower() user.username = user.email.lower() if user.email else None user.first_name = user.first_name.lower() if user.first_name else None user.last_name = user.last_name.lower() if user.last_name else None user.avatar = user.avatar if user.avatar else None if user.first_name and user.last_name: random_string = generate_random_string() slug = slugify(f"{user.first_name} {user.last_name} {random_string}") while User.objects.filter(slug=slug).exists(): random_string = generate_random_string() slug = slugify(f"{user.first_name} {user.last_name} {random_string}") user.slug = slug user.set_password(decrypted_data["password"]) user.password2 = None user.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
额外注意事项
- ECB模式风险:AES-ECB模式安全性较低,建议改用CBC或GCM模式,同时添加随机IV(初始化向量),进一步提升安全性。
- 密钥存储:不要把密钥硬编码在前端代码中,前端可以从后端获取临时密钥或使用HTTPS确保传输安全。
内容的提问来源于stack exchange,提问作者Olasubomi
相关产品推荐
相关产品推荐

