DEV Community

Cover image for Python y firma XML
1N0T
1N0T

Posted on

Python y firma XML

Vamos a ver, cómo firmar documentos XML y, cómo validar si el contenido de un documento firmado, se mantiene inalterado o, por el contrario, ha sufrido alguna modificación.

Como no puede ser de otra manera, lo primero que vamos a hacer es crear un nuevo entorno virtual y a activarlo.

mkdir firmaXML cd firmaXML python3 -m venv venv source venv/bin/activate 
Enter fullscreen mode Exit fullscreen mode

Ahora instalamos las librerías que vamos a necesitar.

pip install pip --update pip install lxml pip install signxml 
Enter fullscreen mode Exit fullscreen mode

Para poder proceder a firmar documentos, deberemos disponer de un certificado x509, aunque podemos crear uno autofirmado con el siguiente comando:

openssl req -x509 -nodes \ -subj "/CN=Certificado autofirmado" -days 365 \ -newkey rsa \ -keyout clave_privada.key \ -out clave_publica.crt 
Enter fullscreen mode Exit fullscreen mode

Ya estamos en disposición de crear un ejemplo de como firmar un XML.

from lxml import etree from signxml import XMLSigner, XMLVerifier from signxml.exceptions import InvalidSignature # Nuestro contenido XML XML = """ <test> Contenido importante </test> """ # Recuperamos nuestras claves de certificado.Para la firma, se necesitan tanto la # clave pública como la privada. Para la validación, sólo se requiere la pública. clave_publica = open("clave_publica.crt", "r").read() clave_privada = open("clave_privada.key", "r").read() # Construimos un objeto XNL a partir de string con el contenido nodo_raiz = etree.fromstring(XML) # Creamos objeto XML firmado nodo_raiz_firmado = XMLSigner().sign( data=nodo_raiz, key=clave_privada, cert=clave_publica ) # Convertimos objeto XML a formato string y lo guardamos en fichero para comprobar después # que se produce un error si manipulamos su contenido XML_firmado = etree.tostring(nodo_raiz_firmado, pretty_print=True).decode() with open("XML_firmado.xml", "w") as f: f.write(XML_firmado) # Validamos integridad del contenido XML try: XML_validado = XMLVerifier().verify( data=etree.fromstring(XML_firmado), x509_cert=clave_publica ).signed_xml except InvalidSignature as err: print("ERROR validando integridad XML") exit() print("=== XML original =============================================================") print(XML) print("=== XML firmado ==============================================================") print(XML_firmado) print("=== XML validado =============================================================") print(etree.tostring(XML_validado, pretty_print=True).decode()) 
Enter fullscreen mode Exit fullscreen mode

Creo que el código es bastante autoexplicativo y no necesita de una mayor esplicación. Tras su ejecución, dispondremos de un fichero llamado XML_firmado.xml. Por lo que ahora, ya podemos proceder a comprobar la integridad del fichero.

from lxml import etree from signxml import XMLSigner, XMLVerifier from signxml.exceptions import InvalidSignature # Recuperamos contenido fichero XML XML = open("XML_firmado.xml", "r").read() # Para la validación, sólo se requiere la clave pública. clave_publica = open("clave_publica.crt", "r").read() # Construimos un objeto XNL a partir de string con el contenido nodo_raiz = etree.fromstring(XML) # Validamos integridad del contenido XML try: XML_validado = XMLVerifier().verify( data=etree.fromstring(XML), x509_cert=clave_publica ).signed_xml except InvalidSignature as err: print("ERROR validando integridad XML") exit() print("=== XML original =============================================================") print(XML) print("=== XML validado =============================================================") print(etree.tostring(XML_validado, pretty_print=True).decode()) 
Enter fullscreen mode Exit fullscreen mode

Si lo ejecutamos, sin haber modificado el fichero, y después de haber realizado alguna modificación del contenido, podremos observar la diferencia.

Como puedes comprobar, la cosa es bastante simple ¿no?

Top comments (0)