python:2.7 Django:1.6 pip install redis
En ce qui concerne les pages dédiées, la connexion + les cookies sont courants avec les comptes, mais il y a des moments où vous souhaitez émettre une URL dédiée pour chaque utilisateur sans vous connecter. Par exemple, nous ne délivrons pas de compte aux utilisateurs car il est courant de ne pas émettre d'identifiant de connexion pour les e-mails au moment de l'inscription initiale ou pour les jeux récents sur smartphone.
J'ai peur des attaques par dictionnaire et des attaques à tour de rôle, donc ça devrait être bien si vous prenez des mesures contre cela
↓ Il est probablement plus rapide de lire le code
m.py
from uuid import uuid4
# 1.Émission d'une pièce d'identité jetable
_uuid4 = str(uuid4())
print 'uuid4:', _uuid4
# 2.Pouce de contrôle d'identité jetable
uuid4_char_list = [ord(_char) for _char in _uuid4]
print 'uuid4_char_list:', uuid4_char_list
checksum = sum(uuid4_char_list)
print 'checksum:', checksum
# 3.Émission d'URL
print "http://hoge/page?token={}%20cs={}".format(_uuid4, checksum)
Résultat d'exécution
> python m.py 
uuid4: 6da25bb0-5d9c-4c1e-becc-51e3d5078fe4
uuid4_char_list: [54, 100, 97, 50, 53, 98, 98, 48, 45, 53, 100, 57, 99, 45, 52, 99, 49, 101, 45, 98, 101, 99, 99, 45, 53, 49, 101, 51, 100, 53, 48, 55, 56, 102, 101, 52]
checksum: 2606
http://hoge/page?token=6da25bb0-5d9c-4c1e-becc-51e3d5078fe4%20cs=2606
Lors de la révision, on dit souvent: «N'est-il pas dangereux d'être analysé comme une somme de contrôle? 』
Je vais arranger la logique en endurant l'endroit où je veux dire qu'il n'y a pas de pirate étrange qui analyse notre système dépeuplé.
m.py
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import binascii
from uuid import uuid4
def checksum_base64_crc(_str):
    """
Inverse la chaîne saisie, l'encode en base64 et renvoie la somme de contrôle crc32
    :param _str: str
    :rtype : int
    """
    #Inverser
    _str_r = _str[::-1]
    #base64 encoder et prendre la somme de contrôle crc32
    return binascii.crc32(binascii.b2a_base64(_str_r))
# 1.Émission d'une pièce d'identité jetable
_uuid4 = str(uuid4())
print 'uuid4:', _uuid4
# 2.Pouce de contrôle d'identité jetable
checksum = checksum_base64_crc(_uuid4)
print 'checksum:', checksum
# 3.Émission d'URL
print "http://hoge/page?token={}%20cs={}".format(_uuid4, checksum)
Résultat d'exécution 2
>python m.py 
uuid4: 6a1d87e0-0518-4aa0-a2ca-cced091f254b
checksum: -2147023629
http://hoge/page?token=6a1d87e0-0518-4aa0-a2ca-cced091f254b%20cs=-2147023629
Si les jetons sont trop émis, j'ai peur que la base de données augmente. Il est pratique de gérer des données qui disparaissent avec le temps et qui n'ont aucun problème avec redis. Étant donné que les données disparaîtront avec le temps, ce sera plus facile plus tard si vous conservez l'URL émise comme contre-mesure contre les demandes dans le journal.
token_manager.py
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import binascii
from redis import Redis
from uuid import uuid4
def checksum_base64_crc(_str):
    """
Inverse la chaîne saisie, l'encode en base64 et renvoie la somme de contrôle crc32
    :param _str: str
    :rtype : int
    """
    #Inverser
    _str_r = _str[::-1]
    #base64 encoder et prendre la somme de contrôle crc32
    return binascii.crc32(binascii.b2a_base64(_str_r))
class IncorrectCheckSumError(Exception):
    #Somme de contrôle incorrecte
    pass
class TokenExpiredError(Exception):
    #Le jeton a expiré
    pass
class TokenRepository(object):
    """
Le jeton pour l'URL est stocké et géré dans Redis pendant une certaine période de temps
    """
    EXPIRE_SEC = 3600
    _KEY_BASE = "project_name/url/disposable/{}"
    _cli = None
    @property
    def client(self):
        """
        :rtype : Redis
        """
        if self._cli is None:
            self._cli = Redis(host='localhost', port=6379, db=10)
            return self._cli
        return self._cli
    def get_key(self, token):
        return self._KEY_BASE.format(str(token))
    def set(self, token, value):
        self.client.setex(self.get_key(token), value, self.EXPIRE_SEC)
        return
    def get(self, token):
        """
Renvoie la valeur associée
        :param token:
        :return: str
        """
        value = self.client.get(self.get_key(token))
        return str(value)
    def exist(self, token):
        """
Vérifier si le jeton existe dans le référentiel
        :param token: unicode or string
        :rtype: bool
        """
        return bool(self.get(token))
class TokenManager(object):
    @classmethod
    def validate(cls, token, check_sum):
        """
Vérifiez si le jeton est correct
        :param token: unicode or str
        :param check_sum: int
        :rtype : bool
        """
        token = str(token)
        check_sum = int(check_sum)
        #Vérifiez si le jeton est correct avec la somme de contrôle
        if checksum_base64_crc(token) != check_sum:
            raise IncorrectCheckSumError
        user_id = TokenRepository().get(token)
        return bool(user_id)
    @classmethod
    def generate(cls, user_id):
        """
Générer un jeton et une somme de contrôle
        :param user_id:
        :return: str, int
        """
        #produire
        token = str(uuid4())
        #Jeton et utilisateur générés_Enregistrer l'identifiant en l'associant à redis
        TokenRepository().set(token, user_id)
        return token, checksum_base64_crc(token)
    @classmethod
    def get_user_id_from_token(cls, token, check_sum):
        """
du jeton à l'utilisateur_Soustraire l'ID
        :param token: str or unicode
        :param check_sum: int
        :rtype: str
        """
        token = str(token)
        if not cls.validate(token, check_sum):
            raise TokenExpiredError
        return TokenRepository().get(token)
# 1.Émettre une URL jetable
url_base = "http://hogehoge.com/hoge?token={}&cs={}"
user_id = "1111222333"
_token, check_sum = TokenManager.generate(user_id)
url = url_base.format(_token, str(check_sum))
print url
# 2.Test routier
assert TokenManager.get_user_id_from_token(_token, check_sum) == str(user_id)
Vue côté Django
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
from django.http import HttpResponse
from django.views.generic import View
class ExclusiveView(View):
    def get(self, request, *args, **kwargs):
        # HTTP GET
        token = request.GET.get("token", None)
        check_sum = request.GET.get("cs", None)
        #du jeton à l'utilisateur_Soustraire l'ID
        error_message = None
        message = None
        try:
            user_id = TokenManager.get_user_id_from_token(token, check_sum)
            message = "Votre utilisateur_id est{}est".format(user_id)
        except IncorrectCheckSumError:
            error_message = "Paramètre illégal"
        except TokenExpiredError:
            error_message = "Page expirée"
        if error_message:
            message = error_message
        return HttpResponse(message,
                            mimetype='text/html; charset=UTF-8',
                            *args, **kwargs)
Émission d'URL
>python m.py 
http://hogehoge.com/hoge?token=e359b20e-4c60-48da-9294-2ea9fcca0a6c&cs=-2066385284
■ Accès avec navigateur Système normal

■ Accès avec navigateur Système anormal

Recommended Posts