Python Seguridad
& Criptografía
José Manuel Ortega | @jmortegac
https://speakerdeck.com/jmortega
Security Conferences
Agenda
Introducción a la criptografía1
OWASP & Best Practices4
Seguridad en Django3
PyCrypto y otras librerías2
Tools5
definiciones
 Clave: Permite encriptar y
desencriptar los datos
 TextoPlano: Informatión que
quieres mantener en secreto
 Texto Cifrado: Información
de forma encriptadada
 Algoritmo de cifrado:
convierte texto plano a
cifrado y viceversa
advanced
Salt – Secuencia aleatoria que
se añade a la password
IV (initialization vector) –
previene ataques de
diccionario o mediante
rainbow tables
Derived Key – Fortalece la
generación de claves para que
los ataques de fuerza bruta
tengan menos éxito.
Introducción a la criptografía
Cifrado de césar
Funciones hash(MD5,SHA)
Cifrado simétrico(AES)
Cifrado asímétrico(RSA)
PBKDF2-Key derivation function
Cifrado césar
Funciones hash
Comprobar integridad de ficheros
Generar passwords
Firma digital
MD5
SHA-1
SHA-2(256 and 512 bits)
SHA-3
Funciones
hash
MD5 SHA1
Hashlib functions
https://docs.python.org/2/library/hashlib.html
>>03187564433616a654efef944871f1e4
>>bd576c4231b95dd439abd486be45e23d47a2cbb74b5348b3b113cef4746
3e15a
>>d47b290aa260af8871294e1ad6b473bd48b587593f8dea7b1b5d9271df12
ee08185a13217ae88e95d9bd425f3ada0593f1671004a2b32380039d3c88f68
5614c
>>8fadab23df7c580915deba5c6f0eb75bd32181f55c547a2b3999db0553980
95c33f10b75c823a288e86636797f71b458
Hashlib functions
print(hashlib.algorithms_available)
print(hashlib.algorithms_guaranteed)
MD5 hash function
Comprobar integridad en ficheros
>>d41d8cd98f00b204e9800998ecf8427e
Hash passwords en DB
Websites almacenan el hash de la password
hashlib.sha256(‘password').hexdigest()
>>'5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d15
42d8'
Hash passwords en DB
Hash identifier
https://code.google.com/p/hash-identifier
Cifrado simétrico
AES
Clave compartida
cipher
key size (bytes in
ASCII)
AES-128 128 bits (16 bytes)
AES-192 192 bits (24 bytes)
AES-256 256 bits (32 bytes)
Cifrado asimétrico
RSA
2 claves(pública y privada)
Clave pública(Pk) encriptar
Clave secreta(Sk) descifrar
La clave pública se puede generar a
partir de la clave secreta
Cifrado asimétrico
Encriptación vs Firma
EncriptaciónUsas su clave pública para
enviar un mensaje y el destinatario usa su
clave privada para leerlo.
FirmaPara firmar usas tu clave privada, y
el destinatario usa tu clave pública para
verificar que la documento lo ha firmado
quién dice ser.
PyCrypto
Operaciones Hash
Cifrados AES,RSA
Firma digital
>> pip install pycrypto
https://pypi.python.org/pypi/pycrypto
PyCrypto AES
>>>
d1a2ea7f9661fae8b46b3904b0193ab81516653f73216dfeb5f51afde3d405b2
a secret message
PyCrypto PBKDFimport Crypto.Random
from Crypto.Protocol.KDF import PBKDF2
password = 'europython'
iterations = 5000
key = ''
salt = Crypto.Random.new().read(32)
key = PBKDF2(password, salt, dkLen=32, count=iterations)
print 'Random salt (in hex):'
print salt.encode('hex')
print 'PBKDF2-derived key (in hex) of password after %d iterations: ' % iterations
print key.encode('hex')
Random salt (in hex):
724138b9d987a04bf05d285db678824f9b7e2b1232229711c2e0e2e556a0c19a
PBKDF2-derived key (in hex) of password after 5000 iterations:
d725de7de88e27d16c9c4f224d4c87159735708419d1c949074962b48ce26900
PyCrypto RSA
from Crypto.PublicKey import RSA
def generate_RSA(bits=1024):
#Generate an RSA keypair with an exponent of 65537 in PEM format
#param: bits The key length in bits
#Return secret key and public key
new_key = RSA.generate(bits, e=65537)
public_key = new_key.publickey().exportKey("PEM")
secret_key = new_key.exportKey("PEM")
return secret_key, public_key
PyCrypto RSA
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYS9ITbjKu5i9i36FgzKg/HO3o
6CKGJ1c5E57qVlmYF6L1BcgH+eE+XiwJ6fWyShaVnZDuvUapWgQeOGZ60QBJ/vpu
DdwqsuGoTeJNqaRT9ButJa+o+0tchRKBcM6zKUXYWc7kdAlxEpO2OXZEqxD7bd1O
oxv7mEjqBpVXgNEVrwIDAQAB
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCYS9ITbjKu5i9i36FgzKg/HO3o6CKGJ1c5E57qVlmYF6L1BcgH
+eE+XiwJ6fWyShaVnZDuvUapWgQeOGZ60QBJ/vpuDdwqsuGoTeJNqaRT9ButJa+o
+0tchRKBcM6zKUXYWc7kdAlxEpO2OXZEqxD7bd1Ooxv7mEjqBpVXgNEVrwIDAQAB
AoGAc0qqzTTWP5tYciRTmeE02RqAbJoXULHFkRruaf5WsxHptk3bIVakkr9d3V91
NbRqpnby+hjlvly701jlE8LW0QIccII9oWyV6kMSTEJMth9RlXpCbQY285pwg+bF
zyEhQJmjMj1hMDJLQ8dXLCeqXZ37etYGHTT2XQ+q5TOW4YkCQQC5WDQHBhYa/Mzt
UlXemLxv1ERaxt8zmXSX0bKjIkaYMv1SF3FskiN9Rm/zXvil3HuiySBq9g6/fPbN
T1+dtiZTAkEA0lpsRUqamIbii18aBBQGs/FbrUa71ahpoU7+8wXMxNYQBfVGvlzs
J+tKxSecMO196Hl4l5I14ASEs+4wKK5vtQJARe4gmzHRr1cIntY87eKk3nCxZaq5
Vkek9Q86nlB1YEGE0K9lrTgqSb8EyEdh+3qH73CBWboC8H7ew7IZ+nBaXwJBAJEO
K8Vomcz+jvB/B0iyqqChmo+VzGecuCK1f9gEMt21o90H893H5E3u0mO8WdffnciX
I1KaT66ITx5o7SrQh1UCQGqP8B9bpzXjxMuLUJuL1DoRP4QBGHoXokdu8gKAlPzp
ZK8BKRSPRobwlNFlXWfXLAWIFwXIeqOblI20U/oNwNE=
-----END RSA PRIVATE KEY-----
PyCrypto RSA
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
def encrypt_RSA(public_key, message):
key = (public_key, "r").read()
rsakey = RSA.importKey(key)
rsakey = PKCS1_OAEP.new(rsakey)
encrypted = rsakey.encrypt(message)
return encrypted.encode('base64')
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from base64 import b64decode
def decrypt_RSA(secret_key, message):
key = (secret_key, "r").read()
rsakey = RSA.importKey(key)
rsakey = PKCS1_OAEP.new(rsakey)
decrypted =
rsakey.decrypt(b64decode(message))
return decrypted
True
True
True
public_key
<_RSAobj @0x2b56648 n(1024),e>
encrypted data
('Ixe6xff
M$x12xbbx95xeex02xcfx82Imtf+x1fxaeUxbd
v`^x94xfaxe6_x8bxedx8dxa3xabxfc
xaex17x07=|x18xcax18jxc5x1dx01xad`xd6
WExfbUxd1x12x0c-
xb6x9cxc4x07xaax93<xb5zw&x98xa2xdcx8e
x9e-
x06gQxcfxfaxc8r/xd5x98|xd5xcdgxb2xdaxc
d:dxafxdexe2xcdxcdxf5{p`x07xbb~x1bxa4hH
J#ctE6xfaxc3x87x8dxf2O8,xe2W',)
signature
(4457551225498532822476224614591809434350515155
91891632489128677777517559137687341950585284239
00156177220742858645089371096255086061177099810
10383684208407852030676228547937894176702983088
45129573867710532037695915202916476163644289304
67543317371804318093617486393498897888949152557
196686676342045445446511829L,)
decrypt_data EUROPHYTON2015
True
PyCrypto Firma/verificar
Mejores prácticas
Evitar usar algoritmos MD5 /SHA-1
Usar al menos SHA-2(256-512 bits)
Uso de técnicas más avanzadas como Key
Stretching
Prevenir ataques de diccionario o fuerza bruta
for i in xrange(iterations):
m = hashlib.sha512()
m.update(key + password + salt)
key = m.digest()
PBKDF
Cryptography
Soporte para Python 3
Mejora debug y testing
La usan otras herramientas como PyCrypto,
PyOpenssl, Paramiko
$ pip install cryptography
https://cryptography.io
Cryptography https://cryptography.io
Cryptography https://cryptography.io
Cryptography-Symmetric
Seguridad en Django
Configuración SSL del servidor
Vulnerabilidad HeartBleed
Uso de algoritmos de cifrado débiles
Gestión de claves secretas
Autorización / autenticación de usuarios
Manejo de cookies del usuario
Frameworks API REST
Tastypie
django-rest-framework
dj-webmachine
Django-secure package
http://django-tastypie.readthedocs.org/en/latest
http://django-rest-framework.org
http://benoitc.github.com/dj-webmachine
Seguridad en Django
Qué proveen estos frameworks?
Protección Cross-site scripting(XSS)
Protección Cross-site request forgery(CSRF)
Protección SQL Injection
Protección Clickjacking
Soporte SSL/HTTPS
Uso de algoritmos PBKDF2 /SHA256 para el
almacenamiento de passwords
Seguridad en Django
Almacenamiento de passwords
PBKDF2 + SHA256 por defecto
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher')
class PBKDF2PasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the PBKDF2 algorithm (recommended)
Configured to use PBKDF2 + HMAC + SHA256.
The result is a 64 byte binary string. Iterations may be changed
safely but you must rename the algorithm if you change SHA256.
"""
algorithm = "pbkdf2_sha256"
iterations = 30000
digest = hashlib.sha256
def encode(self, password, salt, iterations=None):
assert password is not None
assert salt and '$' not in salt
if not iterations:
iterations = self.iterations
hash = pbkdf2(password, salt, iterations, digest=self.digest)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
https://github.com/django/django/blob/master/django/contrib/auth/hashers.py/
Almacenamiento de passwords
https://www.ponycheckup.com
Seguridad en Django
Seguridad en Django
Seguridad en Django
Mejores prácticas
Usar HTTPS para conexiónes seguras
SSL
Habilitar HTTPS junto con un certificado propio
Forzar HTTPS en todo el dominio
Flags de seguridad para las cookies
Django only send session cookies over HTTPS
SESSION_COOKIE_SECURE = true
CSRF_COOKIE_SECURE_true
Mejores prácticas
Guardar de forma segura claves secretas y
credenciales
Establecer DEBUG=false en producción en
settings.py
Usar ALLOWED_HOSTS en producción y
asignarle aquellos dominios de los cuales se
tenga control
Limitar accesos admin mediante IP filter
ALLOWED_HOSTS =[*]
ALLOWED_HOSTS =['.yourdomain.com']
OWASP
OWASP
SQL injection
Cross site Scripting(XSS)
SQL injection
No confiar en los datos que envía el usuario
Correcto filtrado de los parámetros
Uso de cursores y bind parameter
from django.db import connection
def select_user(request):
user = request.GET['username']
sql = "SELECT * FROM users WHERE username = %s"
cursor = connection.cursor()
cursor.execute(sql, [user])
SQL injection
Django ORM –QuerySets –Models
 Seguridad transparente para el desarrollador
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
>>b = Blog(name=‘My blog', description=‘django security')
>>> b.save()
SQL injection
SQLMAP
Cross site Scripting(XSS)
Permite a un atacante obtener información
de la sesión del usuario
 Usar el sistema de plantillas de renderizado para escapar los
valores que se pintan en las páginas HTML
from django.shortcuts import render
def render_page(request):
user = request.GET['username']
return render(request, ‘page.html', {‘user’:user})
Mejores prácticas Django
Validar datos de formularios con el
paquete Django forms
Peticiones mediante POST
Usar Meta.Fields en ModelForms
Django-moth
https://github.com/andresriancho/django-moth
Tools http://www.pythonsecurity.org
Tools
Tools
Cryptopng-Steganography
https://pypi.python.org/pypi/cryptoPNG/0.1
GitHub https://github.com/jmortega/python-pentesting
GitHub https://github.com/jmortega/python-pentesting
GitHub https://github.com/jmortega/python-pentesting
GitHub https://github.com/jmortega/python-pentesting
Hacking Secret Ciphers with python
Free online
http://inventwithpython.com/hacking/index.html
GitHub https://github.com/jmortega/pycon-security_criptography.git
Thank you!
José Manuel Ortega| @jmortegac

Python Securidad and Criptografia