Cómo implementar certificate pinning en Android sin romper las actualizaciones

Casi todos los incidentes de pinning se parecen: la app funcionaba, el certificado se renovó y las versiones antiguas dejaron de conectar. Se evita con dos decisiones tomadas antes de publicar.

El planteamiento correcto: pinear la clave, no el certificado

Pinear el certificado del servidor obliga a publicar una versión nueva de la app en cada renovación. Pinear el SPKI, es decir el hash de la clave pública, permite renovar el certificado tantas veces como haga falta mientras se conserve el mismo par de claves.

En Android, la forma soportada de hacerlo es Network Security Configuration: un fichero XML declarativo con los pines por dominio, en vez de un TrustManager escrito a mano. Al ser declarativo, es mucho más difícil equivocarse de una forma que desactive silenciosamente la comprobación.

El pin de respaldo no es opcional

Un solo pin es un punto único de fallo. Si esa clave se compromete y hay que sustituirla de urgencia, cualquier versión publicada con ese pin único queda inservible hasta que el usuario actualice, y a los usuarios no se les puede obligar.

La práctica correcta es generar por adelantado un segundo par de claves, guardarlo fuera de línea y publicar su pin junto al del certificado en uso. El día de la rotación las apps ya confían en el nuevo antes de que exista el certificado.

La fecha de expiración es una trampa

Network Security Configuration admite un atributo de expiración para el conjunto de pines. Pasada esa fecha, la comprobación se desactiva y la app vuelve al comportamiento por defecto.

Es una salvaguarda razonable contra dejar tiradas a las versiones antiguas, pero conviene entender lo que significa: una app vieja acaba dejando de estar pineada. Si esa app no está prevista para durar hasta ahí, hay que forzar la actualización antes de esa fecha.

Qué comprobar antes de publicar

  • Que hay al menos dos pines: el de la clave en uso y el de respaldo.
  • Que el respaldo corresponde a un par de claves realmente generado y custodiado, no a un placeholder.
  • Que el pinning se ha probado con un proxy de interceptación y la conexión falla como debe.
  • Que existe un procedimiento escrito de rotación, con quién lo ejecuta y en qué orden.
  • Que se sabe cuántas instalaciones activas hay de cada versión, para calcular el impacto de una rotación de urgencia.

Lo que el pinning no te da

El pinning garantiza que hablas con tu servidor, no que tu servidor esté hablando con tu app. Un atacante que reimplemente el cliente conecta sin problema: no está interceptando nada, está siendo un cliente nuevo. Autenticar al cliente es un problema distinto y se resuelve con mTLS.

Pinning que rota sin publicar versión

Pide acceso a la beta cerrada y pruébalo sobre tu app.