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