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.
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.
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.
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.
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.
Pide acceso a la beta cerrada y pruébalo sobre tu app.