Diseño de aplicación con frontend en C# y backend en puro SQL

Iniciado por z3nth10n, 9 Noviembre 2018, 11:17 AM

0 Miembros y 1 Visitante están viendo este tema.

z3nth10n

Hola, tengo una duda, estoy pensando en realizar una aplicación, y desde que estoy en las prácticas de una empresa de Almería he visto algunas cosillas interesantes que me gustaría llevar a la práctica, pero claro, soy novato y me gustaría saber como de segura sería la siguiente implementación.

Os pongo en situación:

Hace unos meses estuve pensando en una aplicación, la cual ofrecía un panel con diversas funcionalidades (frontend) para los clientes/usuarios de dicha aplicación. Y esta a su vez, tenía que comunicarse con una base de datos. Así que, por temas de seguridad, lo que acabe haciendo, fue una aplicación en C# (backend) que se comunicaba con la base de datos lanzando sentencias SQL contra ella, una API vaya.

Entonces, claro, mi duda está en que si podría saltarme este paso intermedio, y obviar la aplicación backend, ya que es un rollo implementarla.

Lo que se me ha ocurrido, desde que estoy en esta empresa, es que lo más común es usar procedimientos almacenados (Stored Procedures) que están en SQL Server, en Oracle y en MySQL (no es algo especifico de unos cuantos softwares propietarios).

Y he visto, que todas las aplicaciones, llaman a sus procedimientos almacenados desde una API integrada en el mismo frontend. Y sí lo hacen así supongo que será porque es seguro.

Y tiene lógica, ya que realmente tu no estás viendo la sentencia SQL que se está ejecutando, simplemente, el procedimiento almacenado te trae datos, o los inserta, pero de forma controlada.

Es decir, que un hacker, no podría borrar o alterar la base de datos a sus anchas, si no conociese los procedimientos almacenados. Y no tuviese los permisos correspondientes para cada ejecucción.

Con permisos me refiero a que si, el usuario el cual realiza la petición no tiene dentro de una tabla X (donde hay una columna que especifica su rango de permisos) la cual no tiene permisos, este no podría hacer nada.

La idea está en que dentro del mismo procedimiento almacenado, se llame a otro procedimiento almacenado, el cual haga comprobación de credenciales, de rango, etc etc (para el caso de lectura de datos sensibles, insertar, modificar, borrar o alterar la estrctura de tablas (esto último debería de hacerse desde la propia base de datos)).

Ahora, lo que me sigue fallando es el tema del login.

Lo que se me había ocurrido, es lo siguiente, hacer 3 usuarios de SQL:

- Invitado: Este solo tendria acceso a comprobar los credenciales en la tabla correspondiente. Una vez realizada la conexión se le devolveria una string de conexión como usuario. Y se le crearía una string de conexion en otra tabla la cual no tendria acceso.
- Usuario: Este tendria los permisos estandar de un usuario.
- Administrador: Si se requiriese que la propia aplicación tuviese un panel de administración, pues este seria el usuario de conexion a la base de datos.

No me mola el hecho de devolver strings de conexión. Lo que me gustaría sería, que al conectarse el usuario, se le devolviese un objeto con la conexión la cual solo podria usar desde esa propia sesión.

Y lo mejor de todo, es que me gustaría implementar todo esto que digo de forma que un usuario cualquiera solo pudiese acceder a la cuenta de otro usuario si conociese sus credenciales. Por que sería muy sencillo pasarle en vez de una ID de usuario otra ID de usuario y santas pascuas, por ello lo de la string de conexión.

Pero son conceptos que están muy en el aire y no se muy bien como aplicarlos.

Asi que cualquier guía ayuda no estaría de más.

Un saludo y gracias.

Interesados hablad por Discord.

zonahurbana

Hola.

Cita de: z3nth10n en  9 Noviembre 2018, 11:17 AM
Hace unos meses estuve pensando en una aplicación, la cual ofrecía un panel con diversas funcionalidades (frontend) para los clientes/usuarios de dicha aplicación. Y esta a su vez, tenía que comunicarse con una base de datos. Así que, por temas de seguridad, lo que acabe haciendo, fue una aplicación en C# (backend) que se comunicaba con la base de datos lanzando sentencias SQL contra ella, una API vaya.

Entonces, claro, mi duda está en que si podría saltarme este paso intermedio, y obviar la aplicación backend, ya que es un rollo implementarla.

Creo que es lo más común hoy en día.
Puedes aprovechar la misma API para desarrollar luego aplicaciones cliente en cualquier plataforma (web, desktop, móvil).

En lo que respecta a una aplicación móvil, aunque es posible, no es conveniente... ya que la aplicación tendría que establecer una conexión directamente a la BD y esto puede ser un proceso pesado.

Si se trata de una aplicación desktop, se puede hacer la conexión directamente como comentas. Hice esto en varias ocasiones en la universidad, pero nunca me puse a pensar seriamente en la seguridad.

Se me viene a la mente Firebase Databases y Firestore, que son servicios considerados como backend as a service.
Es posible desarrollar aplicaciones sin tener que programar un backend usando los SDK provistos por Firebase y aplicando reglas de validación (aquí hay un ejemplo de un chat que hice en 5 minutos por curiosidad tras ver todo el trabajo que ahorra).

Pero lo cierto es que, si se trata de aplicaciones que soportan operaciones importantes, lo más probable es que a final de cuentas se terminen escribiendo validaciones a nivel de servidor (usando Cloud Functions en el caso de Firebase).


Cita de: z3nth10n en  9 Noviembre 2018, 11:17 AM
Lo que se me ha ocurrido, desde que estoy en esta empresa, es que lo más común es usar procedimientos almacenados (Stored Procedures) [...].

Y he visto, que todas las aplicaciones, llaman a sus procedimientos almacenados [...] en el mismo frontend. Y sí lo hacen así supongo que será porque es seguro.

Y tiene lógica, ya que realmente tu no estás viendo la sentencia SQL que se está ejecutando, simplemente, el procedimiento almacenado te trae datos, o los inserta, pero de forma controlada.

Es decir, que un hacker, no podría borrar o alterar la base de datos a sus anchas, si no conociese los procedimientos almacenados. Y no tuviese los permisos correspondientes para cada ejecucción.

Con permisos me refiero a que si, el usuario el cual realiza la petición no tiene dentro de una tabla X (donde hay una columna que especifica su rango de permisos) la cual no tiene permisos, este no podría hacer nada.

Creo que  hoy en día se siguen 2 enfoques principales.
Muchas aplicaciones tienen la lógica principal y de forma exclusiva escrita sobre una tecnología backend.
Otras tienen gran parte de la lógica escrita a nivel de base de datos, usando Stored Procedures como comentas.
Creo que hay una tendencia de seguir lo primero para aplicaciones web, y lo 2do para aplicaciones de escritorio, aunque ciertamente sin importar la plataforma ambos caminos son viables, e incluso una mezcla de ambos.


Cita de: z3nth10n en  9 Noviembre 2018, 11:17 AM
La idea está en que dentro del mismo procedimiento almacenado, se llame a otro procedimiento almacenado, el cual haga comprobación de credenciales, de rango, etc etc (para el caso de lectura de datos sensibles, insertar, modificar, borrar o alterar la estrctura de tablas (esto último debería de hacerse desde la propia base de datos)).

[...]

- Invitado: Este solo tendria acceso a comprobar los credenciales en la tabla correspondiente. Una vez realizada la conexión se le devolveria una string de conexión como usuario. Y se le crearía una string de conexion en otra tabla la cual no tendria acceso.
- Usuario: Este tendria los permisos estandar de un usuario.
- Administrador: Si se requiriese que la propia aplicación tuviese un panel de administración, pues este seria el usuario de conexion a la base de datos.

No me mola el hecho de devolver strings de conexión. Lo que me gustaría sería, que al conectarse el usuario, se le devolviese un objeto con la conexión la cual solo podria usar desde esa propia sesión.

Qué bueno que mencionaste lo de usar una primera conexión con permisos de invitado, como requerimiento para poder establecer una 2da conexión con más permisos.

Sin ello, existiría la posibilidad (no estoy seguro del cómo, y creo que menos idea  tienen los usuarios finales, pero al ser tecnología client-side debe haber una forma; si sabes cómo, estaría genial que comentes más sobre esto) de sacar provecho a esta conexión que tiene permisos generales.

No creo que sea posible devolver un objeto como comentas. Es decir, no creo que la comunicación con una base de datos o incluso la comunicación con una API funcionen de esa manera.

Ellos devuelven información, que dependiendo del lenguaje y las bibliotecas usadas, se interpretan como objetos o como tipos de datos primitivos... pero creo que la conexión debe establecerse de todas maneras (porque implica algo que ocurre a nivel de red, y un 3ro no puede establecer una conexión por ti).
Que el objeto "conexión" se cree en la BD o en la API y se devuelva funcionando no se puede, y que se devuelva listo para usar, creo que no tiene sentido.
Para esto último, la BD o la API tendrían que conocer detalles técnicos de la aplicación cliente, a fin de devolver bits que se puedan interpretar exactamente como un objeto en el instante en que se recibe.
Pero a final de cuentas, ese objeto tendría que contener el string de conexión, por lo que sería lo mismo.

Lo siento si he aportado más dudas que respuestas jeje.
Me ha parecido una pregunta muy interesante. Veamos si alguien más se anima a compartir su opinión.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

z3nth10n

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
Se me viene a la mente Firebase Databases y Firestore, que son servicios considerados como backend as a service.

Los conozco, pero a mi siempre me ha gustado las implementaciones propias.

Mirando por aquí: https://stackoverflow.com/questions/41676714/using-firebase-in-net y por aquí: https://github.com/ziyasal/FireSharp/#usage veo que hay que especificar una key, espero que no sea la key de seguridad, que sea la que se puede poner en la aplicación de cliente. Le echaré un vistazo más de cerca ya que me han hablado varias veces de FireBase.

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
Pero lo cierto es que, si se trata de aplicaciones que soportan operaciones importantes, lo más probable es que a final de cuentas se terminen escribiendo validaciones a nivel de servidor (usando Cloud Functions en el caso de Firebase).

Entonces... Andamos jodidos paco jajaja porque realmente, es lo que yo pretendo evitar, que accesos para modificar/eliminar datos se haga de forma restringida.

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
Creo que  hoy en día se siguen 2 enfoques principales.
Muchas aplicaciones tienen la lógica principal y de forma exclusiva escrita sobre una tecnología backend.
Otras tienen gran parte de la lógica escrita a nivel de base de datos, usando Stored Procedures como comentas.
Creo que hay una tendencia de seguir lo primero para aplicaciones web, y lo 2do para aplicaciones de escritorio, aunque ciertamente sin importar la plataforma ambos caminos son viables, e incluso una mezcla de ambos.

Yo creo que para aplicaciones de escritorio y juegos que son mis dos focos principales.

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
Sin ello, existiría la posibilidad (no estoy seguro del cómo, y creo que menos idea  tienen los usuarios finales, pero al ser tecnología client-side debe haber una forma; si sabes cómo, estaría genial que comentes más sobre esto) de sacar provecho a esta conexión que tiene permisos generales.

Basicamente haciendo tampering es una opción. (Si se usa los anti-tampers oportunos + ofuscación y alguna que otra herramienta más, puedes hacer una aplicación robusta, aún así sería vulnerable).

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
No creo que sea posible devolver un objeto como comentas. Es decir, no creo que la comunicación con una base de datos o incluso la comunicación con una API funcionen de esa manera.

Si hubiese un backend en C# sería sencillo, simplemente devolviendo el objeto serializado a byte[] por Sockets (he hecho PoC de ello). Pero claro, ya estamos hablando de backends que no quiero desarrollar.

Cita de: zonahurbana en 10 Noviembre 2018, 03:02 AM
Me ha parecido una pregunta muy interesante. Veamos si alguien más se anima a compartir su opinión.

No creo pero bueno jajaja

A fin de cuentas, por lo que veo, tendre que hacer un mini-backend en PHP en el cual se llamen a metodos de lectura de la base de datos (aunque es un coñazo, porque ya no puedo usar ORM para mapear las tablas a objetos), pero bueno.

Si podría hacerlo con C# y definir los objetos en el backend y devolverlos como tal. Encriptandolos con JWT (también he hecho pruebecillas) usando criptografía hibrida. (el cliente tiene una clave publica y otra privada y lo mismo para el servidor, entonces cuando se quieran enviar datos el uno al otro encriptarán con sus correspondientes claves privadas y desencriptaran con sus claves publias, las cuales si pueden ser enviadas a traves de internet sin mayor problema. Además, usando SecureString dentro del cliente podriamos asegurar una gestión idionea por parte del cliente).

Estuve mirando el tema del consumo, ya que es algo que me preocupa, las pruebas que menciono serían hechas en un servidor de 1GB de ram (en un linux de consola). Aunque optimizando la instalación de mono y usando lo justo y necesario de LAMP se podría hacer algo interesante.

A parte, cree una organización en Github, la cual no he promocionado mucho, pero ánimo a cualquiera a que contribuya:

https://github.com/trytohackus

La idea es sencilla, alguien sube algo, y los demás intentan reventar la aplicación como sea que haga falta. Y luego explicar como lo ha hecho.

Un saludo.

Interesados hablad por Discord.