Gestion du cycle de vie session_key et déchiffrement des données utilisateur WeChat

Dans l'écosystème WeChat Mini-Program, la session_key est un élément crucial pour sécuriser les échanges entre le client, les serveurs de WeChat et votre propre backend. Cet article détaille comment maintenir la validité de cette clé et comment traiter les données chiffrées côté serveur.

1. Comprendre le mécanisme de validité de la session_key

La session_key agit comme une clé de chiffrement pour les données sensibles (comme les informations utilisateur ou les numéros de téléphone). Voici les règles essentielles à retenir :

  • Renouvellement : L'appel à wx.login peut invalider l'ancienne session_key. Il ne faut donc l'appeler que lorsque cela est strictement nécessaire.
  • Expiration : WeChat gère l'expiration de manière dynamique. Plus l'utilisateur est actif, plus la durée de vie est prolongée.
  • Vérificasion : L'API wx.checkSession permet de vérifier la validité de la session sans générer de nouvelle clé, évitant ainsi de rompre le cycle de connexion inutilement.

2. Implémentation de la stratégie de connexion (Frontend)

Pour garantir que les requêtes de déchiffrement ne 植物 échouent pas, nous devons vérifier l'état de la session avant d'envoyer des données chiffrées au serveur.

// app.js - Gestion globale de l'authentification
App({
  onLaunch: function () {
    this.performAuthSync();
  },

  performAuthSync: function () {
    wx.login({
      success: (res) => {
        if (res.code) {
          wx.request({
            url: `${this.globalData.apiHost}/v1/auth/login`,
            method: 'POST',
            data: { auth_code: res.code },
            success: (response) => {
              wx.setStorageSync('user_token', response.data.token);
            }
          });
        }
      }
    });
  },

  globalData: {
    apiHost: "https://api.votre-domaine.com"
  }
});

// index.js - Logique de récupération des données utilisateur
const appInstance = getApp();

Page({
  processUserData: function (userInfoEvent) {
    const { iv, encryptedData } = userInfoEvent.detail;

    wx.checkSession({
      success: () => {
        // La session est valide, on envoie les données au backend
        this.dispatchDecryption(iv, encryptedData);
      },
      fail: () => {
        // Session expirée, on reconnecte puis on envoie
        appInstance.performAuthSync();
        // Optionnel : Ajouter une logique de retry ici
      }
    });
  },

  dispatchDecryption: function (iv, encryptedData) {
    wx.request({
      url: `${appInstance.globalData.apiHost}/v1/user/decrypt-profile`,
      method: 'POST',
      data: {
        iv: iv,
        cipher_text: encryptedData,
        token: wx.getStorageSync('user_token')
      },
      success: (res) => {
        console.log("Profil mis à jour :", res.data);
      }
    });
  }
});

3. Déchiffrement des données côté serveur (Python/Django)

Le backend doit utiliser l'algorithme AES-128-CBC pour traiter le cipher_text fourni par le client. Voici une implémentation robuste utilisant pycryptodome.

# views.py - Point d'entrée de l'API
from rest_framework.views import APIView
from rest_framework.response import Response
from django.core.cache import cache
from .security import WeChatDataProcessor

class UserProfileView(APIView):
    def post(self, request):
        payload = request.data
        token = payload.get('token')
        iv = payload.get('iv')
        encrypted_data = payload.get('cipher_text')

        if not all([token, iv, encrypted_data]):
            return Response({"error": "Paramètres manquants"}, status=400)

        # Récupération de la session_key stockée lors du login
        session_info = cache.get(token)
        if not session_info:
            return Response({"error": "Session invalide ou expirée"}, status=401)

        session_key, openid = session_info.split("|")

        try:
            processor = WeChatDataProcessor(app_id="VOTRE_APP_ID", session_key=session_key)
            decrypted_info = processor.decrypt_data(encrypted_data, iv)
            
            # Mise à jour du profil utilisateur
            # UserProfile.objects.filter(wechat_id=openid).update(nickname=decrypted_info['nickName'], ...)
            
            return Response({"status": "success", "data": decrypted_info})
        except Exception as e:
            return Response({"error": str(e)}, status=500)

# security.py - Utilitaire de déchiffrement
import base64
import json
from Crypto.Cipher import AES

class WeChatDataProcessor:
    def __init__(self, app_id, session_key):
        self.app_id = app_id
        self.session_key = base64.b64decode(session_key)

    def decrypt_data(self, encrypted_data, iv):
        encrypted_data = base64.b64decode(encrypted_data)
        iv = base64.b64decode(iv)

        cipher = AES.new(self.session_key, AES.MODE_CBC, iv)
        decrypted_raw = cipher.decrypt(encrypted_data)
        
        # Suppression du padding PKCS7
        padding_len = decrypted_raw[-1]
        decrypted_json = json.loads(decrypted_raw[:-padding_len].decode('utf-8'))

        if decrypted_json['watermark']['appid'] != self.app_id:
            raise ValueError("ID d'application non valide dans le filigrane")

        return decrypted_json

4. Support des Emojis dans la base de données

Les pseudonymes des utilisateurs WeChat contiennent fréquemment des emojis. Pour éviter des erreurs lors de l'insertion en base de données (notamment avec MySQL), il est impératif d'utiliser le jeu de caractères utf8mb4 au lieu de utf8.

# settings.py - Configuration Django pour MySQL
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'wechat_db',
        'USER': 'db_admin',
        'PASSWORD': 'password_secure',
        'HOST': 'localhost',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
        },
    }
}

Notes supplémentaires

Si votre environnement Python ne dispose pas des bibliothèques nécessaires pour les opérations cryptographiques, installez le paquet suivant :

pip install pycryptodome

Cette approche garantit que la communication reste fluide même si la session_key expire pendant que l'utilisateur navigue sur l'application, en automatisant la vérification et la récupération sans impact sur l'expérience utilisateur.

Étiquettes: wechat-miniprogram Python Django aes-decryption mysql-utf8mb4

Publié le 19 juillet à 21h49