¿Por qué no exponer una clave primaria?

53

En mi educación me han dicho que es una idea defectuosa exponer las claves primarias reales (no solo las claves DB, sino todos los accesos primarios) al usuario.

Siempre pensé que era un problema de seguridad (porque un atacante podría intentar leer cosas que no fueran suyas).

Ahora tengo que verificar si el usuario tiene acceso de todos modos, ¿hay alguna razón diferente detrás?

Además, como mis usuarios tienen que acceder a los datos de todos modos, necesitaré tener una clave pública para el mundo exterior en algún punto intermedio. Ahora que la clave pública tiene los mismos problemas que la clave primaria, ¿no?


Se ha solicitado un ejemplo de por qué hacerlo de todos modos, así que aquí hay uno. Tenga en cuenta que la pregunta tiene que ver con el principio en sí, no solo si se aplica en este ejemplo. Las respuestas a otras situaciones son explícitamente bienvenidas.

La aplicación (web, móvil) que maneja la actividad, tiene múltiples IU y al menos una API automatizada para la comunicación entre sistemas (por ejemplo, el departamento de contabilidad quiere saber cuánto cobrar al cliente en función de lo que se ha hecho). La aplicación tiene varios clientes, por lo que la separación de sus datos (lógicamente, los datos se almacenan en el mismo DB) es imprescindible para el sistema. Se verificará la validez de cada solicitud sin importar qué.

La actividad es muy fina, por lo que está unida en algún objeto contenedor, llamémosla "Tarea".

Tres casos de uso:

  1. El usuario A quiere enviar al usuario B a alguna tarea, por lo que le envía un enlace (HTTP) para realizar alguna actividad allí.
  2. El usuario B debe salir del edificio para abrir la tarea en su dispositivo móvil.
  3. Contabilidad quiere cobrar al cliente por la Tarea, pero utiliza un sistema de contabilidad de terceros que carga automáticamente la Tarea / Actividad mediante un código que hace referencia a la REST - API de la Aplicación

Cada uno de los casos de uso requiere (o se hace más fácil si) que el agente tenga algún identificador direccionable para la Tarea y la Actividad.

Angelo Fuchs
fuente
3
relacionado: ¿Debería exponerse una clave sustituta a un usuario? "Debe estar preparado para cualquier identificador que esté expuesto a los usuarios / clientes que necesitan ser cambiados, y cambiar la identidad de una fila en una base de datos y propagar ese cambio a todas las claves externas es solo pedir que rompan los datos ..."
mosquito
@gnat ON UPDATE CASCADEse hizo para eso (¿mysql específico?), aunque si el problema es la seguridad, entonces la verificación de acceso debería estar en el backend y no confiar en el usuario de todos modos
Izkata
2
@Izkata Sí, excepto cuando los referencia en un almacén de datos diferente (ID de usuario en LDAP como un ejemplo simple), o necesita tener que recuperar algunos datos de una copia de seguridad. el mosquito tiene un buen punto allí.
Angelo Fuchs el
¿Puedes dar detalles sobre lo que quieres decir con "exponer"? Un ejemplo real podría ayudar. :-)
CodeCaster
"exponer" significa mostrárselo al usuario. (Por usuario me refiero a un humano principalmente, pero la pregunta parece válida también para máquinas)
Angelo Fuchs

Respuestas:

38

Además, como mis usuarios tienen que acceder a los datos de todos modos, necesitaré tener una clave pública para el mundo exterior en algún punto intermedio.

Exactamente. Tome el HTTP sin estado, que de otro modo no sabría qué recurso debería solicitar: expone la identificación de su pregunta 218306en la URL. ¿Quizás se esté preguntando si un identificador expuesto puede ser predecible ?

Los únicos lugares donde escuché una respuesta negativa a eso, usaron la lógica: "¡Pero pueden cambiar la ID en la URL!" . Entonces utilizaron GUID en lugar de implementar la autorización adecuada.

Me imagino una situación en la que no desea que sus identificadores sean predecibles: la recolección de recursos. Si tiene un sitio que aloja públicamente ciertos recursos en los que otros pueden ser interesantes, y los aloja como /images/n.jpgo /videos/n.mp4donde nsolo hay un número creciente, cualquiera que vea el tráfico hacia y desde su sitio web puede cosechar todos sus recursos.

Entonces, para responder directamente a su pregunta: no, no está mal "exponer" directamente los identificadores que solo tienen significado para su programa, por lo general, incluso es necesario que su programa funcione con éxito.

CodeCaster
fuente
2
Las URL no cuestionables (por ejemplo, que contienen un token de 128 bits criptográficamente aleatorio) son una forma de autorización adecuada.
CodesInChaos
¿Adecuado como extremadamente sensible a ataques de repetición? Es bueno para un uso único como una URL de restablecimiento de contraseña, pero menos para identificar un recurso estático, ya que una vez que el token está abierto, cualquiera puede usarlo, sin que pueda cambiarlo sin romper ninguna referencia legítima a eso.
CodeCaster
hm? Obviamente requiere SSL, pero ese es el caso, no importa cómo se autentique y autorice. A través de SSL, un atacante no puede aprender el token (al igual que no puede aprender cookies) y también evita los ataques de repetición. El principal inconveniente de este enfoque es que no puede revocar el acceso para usuarios individuales, por lo que prefiero usarlo solo para recursos inmutables. Revocar el acceso a recursos inmutables no tiene sentido ya que un atacante podría simplemente almacenar una copia local.
CodesInChaos
2
Parece que soy incapaz en estos días de expresar lo que quiero decir, lo siento. Me refiero a que usar un token aleatorio para un recurso estático en lugar de un ID incremental está bien, si desea que el recurso sea de acceso público pero no adivinable. Para cualquier otro uso, aunque preferiría un uso único, debido a la revocación.
CodeCaster
1
Ninguno, mi punto exactamente. Entonces, ¿puedes explicar qué quieres decir con "exponer"?
CodeCaster
29

No debe exponerlo porque las personas que lo vean comenzarán a usarlo como su 'número de cuenta', que NO es. Por ejemplo, para mi cuenta bancaria sé cuál es mi número de cuenta. Lo he memorizado, lo uso por teléfono con el servicio al cliente, lo uso al completar formularios para que otros bancos hagan transferencias, para documentos legales, para mi servicio de pago automático, etc., etc. No quiero para cambiar La clave principal (para mi cuenta) por otro lado, no lo sé ni lo veo.
El sistema que lo almacena cambia a lo largo de los años de un sistema a otro, a través de fusiones bancarias, actualizaciones y reemplazos del sistema, etc.
Las claves principales pueden cambiar a través de algunas de estas transformaciones, por lo que si nunca se ha expuesto, escrito o recordado por cualquier usuario habitual que '
Las claves sin significado comercial a menudo se denominan claves sustitutas y a menudo (pero no siempre) se utilizan como claves principales.

Por cierto, esto incluso ocurre internamente cuando las personas construyen interfaces y programas que hacen mal uso y exponen claves primarias y los hacen parte de tales sistemas en lugar de que solo hagan una cosa: identificar de forma única un registro de base de datos internamente. De hecho, aprendí lo anterior a través de un período de 6 años apoyando un sistema de almacenamiento de datos en un hospital.

Michael Durrant
fuente
44
+1 pero lo que estás describiendo aquí es en realidad una clave sustituta . No todas las tablas tienen una clave sustituta e incluso si la tiene, puede que no sea la clave "primaria".
nvogel
2
+1 Pensé que el número de cuenta sería la clave sustituta, pero lo leí y estás 100% correcto :)
Michael Durrant
2
+1 exponerlo a los usuarios agrega requisitos implícitos (por ejemplo, permanecer estático)
Matt
1
Gran respuesta. Mi forma abreviada de decir esto es que las claves sustitutas son útiles porque a nadie le importan y, por lo tanto, a nadie le importa si las cambias o no. Si los expones, la gente comenzará a preocuparse por ellos.
JimmyJames
tl; dr: porque el futuro. Si algo externo depende de una clave, las cosas se complican si la implementación cambia más adelante; así que mantenlos más o menos ocultos para facilitar las cosas.
Adam Tolley
27

Porque las claves principales son un detalle de implementación.

Si migra bases de datos, sus claves principales pueden cambiar debido al orden de inserción, eliminación de registros antiguos ... algunas razones diferentes. Si migra plataformas de bases de datos , es posible que ya no tenga una clave primaria real. Exponer la PK por encima de la capa de acceso a datos es una abstracción permeable, con todas las preocupaciones de acoplamiento que conlleva.

Telastyn
fuente
3
¿Cómo una capa de aplicación identificará de manera única un recurso del que desea recuperar o actualizar en la capa de datos sin una clave primaria?
CodeCaster
2
@CodeCaster: ya sea por un conjunto único de datos indexados o por una clave primaria no pública que se devuelve como parte del objeto suministrado por la capa de acceso a datos.
Telastyn
1
@CodeCaster: hay muchas formas de crear un token que permite que la devolución de llamada especifique qué operación se está realizando, y ciertamente no todas ellas simplemente pasan la clave primaria.
Telastyn
2
Pero eso requiere que la capa de datos sepa a qué token pertenece (o se traduce) a qué PK. Para mí eso suena como una capa adicional de complejidad innecesaria, simplemente por el hecho de ocultar el PK. ¿Para qué sirve eso, además de satisfacer al arquitecto? Estoy de acuerdo con su punto, simplemente no lo encuentro aplicable en el uso en el mundo real y agradecería un ejemplo real.
CodeCaster
1
@CodeCaster: no, el nivel medio realmente hace su trabajo y resume que hay acceso a datos desde la IU. Hay muchos arquitectos malos en el mundo, pero muchas de las mejores prácticas de diseño de programas existen por una razón. Algunas aplicaciones pueden correr el riesgo de esa abstracción permeable y otras no.
Telastyn
10

Esta es una respuesta combinada de las otras (también conocida como lo que he aprendido). Si tiene ganas de votar a este, al menos debe votar a uno de los otros tan bien como hicieron el trabajo real. Si está más interesado, lea las otras respuestas en su lugar.

No debe exponer la clave primaria de la base de datos, sino usar una clave sustituta

  1. Si desea que sus usuarios puedan recordar (al menos un poco) o reconocer el identificador de una entrada. ( Respuesta de Graystone28s )
  2. Si desea planificar con anticipación y considera que puede cambiar los sistemas (base de datos o de otro tipo) que probablemente cambiarán su PK. ( Respuesta de Telastyns )
  3. Si desea asegurarse de que sus usuarios tengan una forma coherente de acceder a los datos que no cambiarán incluso si su empresa cambia de propietario y los datos se migran a un sistema completamente diferente. ( Respuesta de Michael Durrants )
  4. Si su PK es predecible (como una secuencia), su sistema puede sufrir problemas de recolección de recursos. ( Respuesta de CodeCasters ) Esto solo se aplica si su sistema tiene información que vale la pena cosechar y que sea accesible por cualquiera o al menos alguien que tenga un interés en la cosecha.

Nota: Su clave creada debe ser (un poco) humanamente comprensible ( Respuesta de Sqlvogels ).

Si su sistema no necesita 1. a 4. entonces no hay razón para no usar las bases de datos PK como su identificador público (varias de las respuestas). Además, la seguridad no es un problema aquí (varias de las respuestas).

Angelo Fuchs
fuente
8

Una de las razones por las que he encontrado es que, en la totalidad del tiempo, he visto a los usuarios finales solicitar que su identificador signifique algo (como tener un prefijo o un indicador del año en que se creó). Cambiar un PK es difícil, pero un sustituto es mucho más fácil.

Es probable que su clave principal sea algo que desea que indexe su base de datos por razones de rendimiento, y puede que a tiempo por razones técnicas la cambie, por ejemplo, de un número a un guid ... simplemente no sabe por qué razones las nuevas tecnologías o el conocimiento podría guiarte hacia abajo. Su paquete es su elemento técnico de datos, la clave pública es para el consumo de los usuarios finales.

Wayne M
fuente
77
La pregunta es: "¿Es malo exponer las claves primarias?" . Su respuesta: "Los usuarios pueden querer tener sus propios identificadores" . No entiendo la relación. Expongo InvoiceNumber, lo que tiene un significado y puede ser cambiado por el cliente, pero también expongo InvoiceID, que mi código utiliza para identificar de forma única la factura. No tiene que (y con mayor frecuencia no quiere ) dejar que la clave de usuario sea la clave de almacenamiento. Esta pregunta es sobre esto último.
CodeCaster
Creo que este es un buen ejemplo porque si te mudas a la versión multiinquilino de tu aplicación, puedes mantener la misma sintaxis y tener varias facturas de la misma InvoiceNumber(para diferentes inquilinos) pero tener diferentes claves principales: un punto (tipo de ) mencionado en la respuesta también.
recluze
1
@CodeCaster esta pregunta es en realidad sobre "¿por qué no quieres que sean iguales"?
Angelo Fuchs el
En ese caso, ver la respuesta de Telastyns .
CodeCaster
2

Para la mayoría de las aplicaciones es bastante esencial que expongas las claves a los usuarios. Para utilizar un sistema de información de manera efectiva, los usuarios de ese sistema normalmente necesitarán una forma de identificar la información dentro de él y relacionar esa información con algo en el mundo fuera de la base de datos. En términos de bases de datos relacionales, esos identificadores son claves.

Un patrón de diseño bien utilizado es crear una clave adicional, puramente "técnica" para las tablas de la base de datos como un medio de abstracción. Por ejemplo, para proporcionar una clave estable (relativamente inmutable) donde alguna clave alternativa está sujeta a cambios. Dichas claves técnicas generalmente no están expuestas a los usuarios finales porque hacerlo socava la abstracción prevista de los requisitos del usuario. No tiene nada que ver con la seguridad.

El problema / malentendido implícito en su pregunta se debe al uso inapropiado del término clave primaria . Una clave primaria es solo una entre varias claves "candidatas" (varios identificadores posibles en una tabla de base de datos). La clave primaria no requiere necesariamente ninguna propiedad fundamentalmente diferente a cualquier otra clave, por lo que las afirmaciones y los principios de diseño que se aplican específicamente a las claves primarias y no a otras claves son siempre sospechosos y, a menudo, incorrectos.

Dado que generalmente necesitará exponer una clave a su usuario, ¿cuál debería ser esa clave? Intenta que tus llaves sean familiares, simples y estables. La familiaridad y la simplicidad hacen que las claves sean fáciles de leer y recordar y ayudarán a evitar errores de entrada de datos. Estabilidad significa que la clave cambia con poca frecuencia, lo que también ayuda a evitar la posibilidad de una identificación errónea.

nvogel
fuente
1
¿De qué depende? Quiero saber cuáles son las razones detrás de ese concepto genérico para saber cuándo aplicarlo y cuándo no.
Angelo Fuchs el
1
Hola cliente, por favor dame tu identificación para que pueda ayudarte. Claro, es gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456. Hmm, ¿qué tal tu social? ... Identificación del sustituto
Michael Durrant
@Michael, Respuesta actualizada. ¿Es una clave familiar, simple y estable?
nvogel
1

Esto es de un comentario sobre la respuesta de Greystone28 por CodeCaster. Es un ejemplo de lo que estás diciendo:

Expongo InvoiceNumber, que tiene un significado y es modificable por el cliente, pero también expongo InvoiceID, que mi código utiliza para identificar de forma única la factura. No tiene que (y con mayor frecuencia no quiere) dejar que la clave de usuario sea la clave de almacenamiento. Esta pregunta es sobre esto último.

¿Qué propósito en su aplicación sirve para reproducir el InvoiceID?

Al exponer, supongo que quiere decir que el usuario puede verlo. Solo exponga si el usuario lo necesita para usar su aplicación. Podría ser utilizado por soporte técnico o algunas cosas administrativas. He trabajado con algunas aplicaciones que hacen esto. Hace que sea más fácil proporcionar soporte cuando conozco el registro específico en cuestión.

JeffO
fuente
Las facturas tienen identificadores naturales (números) pero solo para los que usted escribe. ¿Qué pasa con los que obtienes? Tienen InvoiceNumbers pero se superponen (porque dos compañías usan el mismo y ambos le envían una factura). En esta situación, su InvoiceID es único, el Número no lo es y lo que lo hace único sería el Nombre del cliente, que no es un buen identificador de datos (demasiado largo, cambia con demasiada frecuencia, puede contener caracteres oscuros ...)
Angelo Fuchs
@AngeloNeuschitzer: si el usuario puede identificar de forma exclusiva una factura por nombre y número de Cliente, el usuario no necesita el PK InvoiceID, pero la base de datos y el código subyacente pueden usarlo. Son funciones mutuamente excluyentes.
JeffO
Véanse los casos 1 a 3 de mi ejemplo. En ninguno de esos casos, el Nombre del cliente es una forma útil de abordar ese Objeto para el Usuario (ya sea humano o máquina). Factura ID PK es.
Angelo Fuchs el
1

Es completamente normal que las entidades tengan un identificador único que esté expuesto al mundo exterior. Para algunos objetos, es posible encontrar un identificador que realmente tenga un significado (por ejemplo, número de factura) pero para otros no existe dicho identificador y, por lo tanto, debe generarse.

En aras de la coherencia y la legibilidad, considero que es una buena práctica que todas las entidades de un sistema utilicen exactamente el mismo tipo y nombre para su identificador. Normalmente este identificador estaría expuesto ( <type> getId()) en alguna clase base abstracta.

Por la misma razón, cada servicio en el sistema (por ejemplo, servicio de factura) debe proporcionar métodos idénticos para acceder a las entidades por su identificador. Normalmente, este método ( findById(<type> id)) se heredaría de una interfaz de servicio genérica o una clase base.

Este identificador no tiene que ser la clave principal de la entidad, pero puede ser una. Lo único que hay que asegurarse es que la estrategia de generación de claves produce identificadores razonablemente únicos (no necesariamente universalmente únicos, pero al menos dentro del sistema).

Si el sistema se migra más tarde (si es grande, según mi experiencia) a otra base de datos, no es un problema usar una estrategia diferente (no basada en claves primarias) para crear los identificadores siempre que la estrategia sea compatible con la original.

Cordero
fuente
¿Podría explicar qué en su respuesta no se ha respondido en las otras?
Angelo Fuchs
2
En mi respuesta, no estoy de acuerdo al menos con los puntos 2. y 3. de su resumen. No creo que estas sean razones válidas para no usar PK como identificadores de objeto.
Muton
0

La clave principal está allí, solo como un identificador de la tupla (registro, fila) a la que intenta acceder como desarrollador. También se usa en integridad referencial (restricciones de clave externa), y quizás también tenga uno o más casos de uso.

Esencialmente, no hay nada malo en exponerlo a los usuarios, o incluso a los hackers. Porque no sé de un ataque que usa la clave primaria, por ejemplo.

Pero en seguridad, tenemos muchos principios (que aceptamos y no aprobamos) y debemos cumplirlos:

  1. El principio del privilegio de arrendamiento
  2. Seguridad a través de la oscuridad

Y algunos otros principios. Lo que dicen esencialmente es que:

Si no necesita exponer sus datos, ¿por qué lo haría?

Saeed Neamati
fuente
La parte del mango es donde estoy de acuerdo. La seguridad no es. Que podría ser relevante para la seguridad, pero tener una clave interna independiente que no es visible para el usuario no es realmente sobre todo por la seguridad. Yo llamaría a eso un buen efecto secundario.
JensG
¿Por qué: ver el ejemplo que agregué a la pregunta?
Angelo Fuchs el