You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

问题根源及解决步骤

核心问题

  1. 前后端加密逻辑不匹配:前端单独加密每个字段,后端却期望接收一个名为encryptedPayload的完整加密 payload,两者完全不对接。
  2. 密钥处理不一致:CryptoJS默认会对传入的密钥做SHA-256哈希处理后再作为AES密钥,而后端直接解码base64密钥,导致两边密钥实际不同。
  3. 请求格式错误:前端用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 21:32:05