Questo è un problema comune nello sviluppo di applicazioni di database, con alcune soluzioni valide.
In primo luogo, solo per dirlo, un singolo account SQL per l'applicazione, con le autorizzazioni per fare tutto ciò che il programma è capace, è cattivo. Doppiamente male quando le credenziali di questo account sono codificate nella tua app per consentire la connessione. Il motivo per cui è esattamente la ragione per cui ti posizioni; qualcuno potrebbe alimentare le credenziali in una console SQL ed eseguire delete * from User
per spazzare via il tuo sistema di sicurezza.
La prima soluzione possibile è non concedere diritti CRUD per account non amministratori alle tabelle e, naturalmente, non inserire mai hard-code o fornire un account amministratore al software client. Invece, i diritti di lettura possono essere concessi con autorizzazioni SELECT sulle viste e diritti C_UD tramite le autorizzazioni EXECUTE sulle stored procedure. Questa è una soluzione vecchia e ampiamente accettata, ed è ancora utilizzata anche se le migliori pratiche per la maggior parte delle lingue e degli ambienti ora incoraggiano altri pattern.
La seconda soluzione è simile in teoria ma diversa nell'implementazione; implementare un endpoint del livello di servizio che definisce le possibili operazioni dei dati. Questa è la nuova best practice, specialmente per situazioni che comportano un utilizzo "anonimo" sulle reti pubbliche (servizi web). Invece del client che si connette al DB, il client stabilisce un canale di servizio per l'endpoint e da quel punto può solo chiamare i metodi che il livello di servizio consente e può anche essere richiesto di passare i dati di autenticazione come un token per fare qualsiasi chiamata dati diversa dal login iniziale.
I lati negativi di entrambi gli approcci precedenti sono che probabilmente dovrai apportare modifiche radicali al tuo accesso ai dati lato client per chiamare stored procedure o metodi di servizio invece di operazioni dirette basate su tabella. Ora hai anche una logica di business sul lato server e persino nel livello dati, in relazione al fatto che gli utenti possano fare solo ciò che dovrebbero e non stanno cercando di fare ciò che non dovrebbero. Infine, per necessità, si restringe l'ambito delle operazioni di recupero dei dati validi esponendo metodi di accesso specifici, un passo indietro nella progettazione DAL per la maggior parte dei linguaggi moderni come .NET e Java (che hanno ORM come Hibernate e Entity Framework per fornire query complesse abilità senza "stringhe magiche").
L'ultima soluzione richiede la minima implementazione ma può essere più vulnerabile; l'account utente hard-coded nel client ha le autorizzazioni minime necessarie per verificare le credenziali di un utente (idealmente essendo dato i diritti EXECUTE a una singola stored procedure "PerformLogin"). Come parte dell'autenticazione utente, dopo aver verificato le credenziali, la routine restituirà le credenziali SQL di un utente DB con le autorizzazioni correlate ai dati correlate a ciò che l'account utente autenticato è autorizzato a fare. Il software client quindi si riconnette al database dopo l'autenticazione utilizzando le credenziali fornite. Il vantaggio rispetto ad altre soluzioni è che sono necessarie solo piccole modifiche al livello di persistenza (e una riconnessione dopo l'autenticazione è riuscita) per implementarlo nel sistema corrente di una connessione DB diretta e operazioni di tabella, invece di modifiche più profonde a come ottenere i dati invocando stored procs o un servizio.
Gli svantaggi sono che gli utenti SQL disponibili tramite l'autenticazione devono rappresentare utili sezioni trasversali di funzionalità, in genere prestando la struttura complessiva più a "livelli" di autorizzazioni utente invece di uno schema "a la carte" più modulare. Mezzi per mitigare questo (come la creazione e l'impostazione dinamiche di permessi su un utente dopo l'autenticazione) sono tipicamente i loro stessi worm da un punto di vista della sicurezza. Avrai comunque bisogno di molti utenti "built-in", uno per ogni livello, perché questo processo di connessione in due fasi abbia un valore reale (se l'utente Johnny ha il livello utente più basso, ma solo autenticandosi ottiene un account utente SQL amministratore per il resto della sua sessione, il tuo client è ora l'unico livello di sicurezza e, come abbiamo discusso, può essere facilmente aggirato). Infine, anche con account utente SQL ben personalizzati, le autorizzazioni necessarie possono essere ancora piuttosto ampie; I diritti UPDATE su una tabella sono necessari affinché il client aggiorni un record, ma possono essere utilizzati malintenzionalmente dall'attaccante da una console per escluderli tutti. Le altre soluzioni limitano molto specificamente le operazioni di dati consentite per entrambi gli approcci.