Come gestite la sicurezza del database da un'applicazione desktop?


12

Per circa 10 anni ho lavorato su varie applicazioni client desktop interne con archivi dati di SQL Server. Raramente ho iniziato questi progetti - la maggior parte sono lavori di acquisizione.

Una cosa che sembrava costante dappertutto era che esisteva un unico account utente globale di SQL Server che questa applicazione usava che gli concedeva l'autorizzazione per il database comune, e sì in alcune situazioni ingenue utilizzava l' saaccount utente, che in genere cercavo di correggere quando possibile .

Non è possibile nascondere in modo efficace questo nome utente e password utilizzati dall'applicazione per accedere al database. Sono di solito conservati in un inio configdi file, o, eventualmente, cotto in dell'eseguibile stesso. In tutti i casi, sono visibili all'utente se eseguono un po 'di scavo. In un caso abbiamo effettivamente utilizzato un configfile ma crittografato, ma ovviamente la chiave di crittografia doveva essere memorizzata nell'eseguibile (non eravamo ingenui nei limiti di questo, ma impediva effettivamente alle persone di frugare in chi era abbastanza esperto per cercare nei configfile).

Tutti questi sistemi avevano un sistema di autenticazione utente integrato nell'applicazione, ma ovviamente erano tutti gestiti attraverso l'applicazione stessa, il che significa che le informazioni dell'utente erano archiviate nel database. L'applicazione limitava ciò che potevi fare in base al tuo livello di accesso, ma è tutto un po 'discutibile se riesci a connetterti al database ed eseguire query ad hoc.

Sono interessato a sapere cosa fanno gli altri sistemi per aggirare questo problema. Ecco le opzioni che conosco:

  1. Utilizzare il meccanismo di sicurezza di SQL Server per mantenere un elenco di utenti e ruoli e fare in modo che l'applicazione desktop aggiunga e rimuova gli utenti tramite query T-SQL.
  2. Invece di collegarti direttamente al database, crea un qualche tipo di servizio web che gira sul server e inserisci la logica di autenticazione. Fai in modo che ogni richiesta esegua la convalida della sicurezza.

Le prime opzioni sono un po 'brutte perché stai separando gli utenti dal database, quindi gli utenti non sono più entità di prima classe e non puoi fare riferimento a loro con relazioni di chiave esterna, ecc.

Il secondo sembra solo un grave problema di prestazioni e un sacco di lavoro extra, inoltre non è possibile utilizzare facilmente i mapper ORM come NHibernate (penso).

Qualcuno ha esperienza con questo? Migliori pratiche?

modificare

Pensando un po 'di più, l'autenticazione di SQL Server può effettivamente risolvere questo problema? Ad esempio, se l'utente deve essere in grado di inserire e aggiornare i record della scheda attività in modo da poter modificare la scheda attività, non è possibile in alcun modo che SQL Server possa impedire l'accesso ad altre righe nella tabella dei dettagli della scheda attività, il che significa che è possibile leggere e scrivere anche le schede attività di altre persone.


Sul tema degli attacchi; non usare ORM come NHibernate è (penso) un problema. Se usi i servizi web come esempio, troverai molti modi per legare in modo efficiente i tuoi dati a XML.
jasonk,

Non dovresti comunque utilizzare il tuo ORM come mapping diretto tra oggetti business ed entità DB, è un approccio scadente che rende fragili le interfacce. Invia richieste a un livello aziendale che ottiene entità DB non elaborate e restituisce al client solo i dati richiesti.
gbjbaanb,

@gbjbaanb - certo, cambierò l'intera architettura questo pomeriggio. :)
Scott Whitlock,

Suppongo che potresti aspettare fino a quando qualcuno ti hackererà prima di cambiarlo, ma il lato
positivo

È possibile impedire a un utente di aggiornare i record di qualcun altro, utilizzando una procedura memorizzata come unico modo per aggiornare i record e utilizzando l'utente che esegue il proc come parte della query. Vedi CURRENT_USER
gbjbaanb,

Risposte:


9

Temo che l'aggiunta di un livello di servizio Web sia probabilmente la soluzione corretta al tuo problema.

Separare il client dall'implementazione del database sottostante probabilmente ti aiuterà anche nel lungo periodo.

L'aggiunta di un livello di servizio Web non deve necessariamente danneggiare le prestazioni ...

In effetti, con un'API appropriata, un servizio Web può effettivamente migliorare le prestazioni raggruppando più query di database all'interno della LAN del data center, anziché richiedere più round trip sulla WAN.

E, naturalmente, un livello di servizio Web può spesso essere ridimensionato in orizzontale e aggiungere una cache adeguata alle query del database, forse anche un meccanismo di notifica delle modifiche.

Un livello server aggiunge sicurezza che non è possibile garantire con le app in esecuzione su un client remoto. Tutto ciò che viene eseguito su un client può essere "hackerato" e non dovrebbe essere considerato in alcun modo affidabile. Dovresti solo inserire la logica di presentazione nel client e ospitare qualsiasi cosa importante sull'hardware di cui hai il controllo completo.

Non conosco le tue app, ma le mie app Web sono naturalmente suddivise in più livelli, con il codice di presentazione separato dal livello di persistenza da almeno un livello di logica aziendale che tiene separati i due. Trovo che questo renda molto più facile ragionare sulla mia app e molto più veloce di aggiungere o modificare funzionalità. Se i livelli sono separati comunque, è relativamente facile mantenere il livello di presentazione nel client e il resto su un server sotto il mio controllo.

Quindi, mentre puoi risolvere i tuoi problemi senza introdurre un livello di "servizio web", quando avrai scritto tutte le procedure memorizzate (o equivalenti) necessarie per riempire i buchi nell'implementazione della sicurezza del database standard, probabilmente staresti meglio scrivendo un'applicazione lato server per la quale è possibile scrivere test unitari adeguati.


Ammetto che non deve essere un collo di bottiglia nelle prestazioni, ma aggiunge sicuramente un ulteriore livello all'architettura, il che significa molta più manutenzione.
Scott Whitlock,

3
Aggiunge un livello, ma non necessariamente manutenzione. Considerare che con tutta la logica inserita nel servizio, non il client, le modifiche possono essere "implementate" senza richiedere agli utenti di aggiornare le loro applicazioni client.
GrandmasterB,

5

Simile alla risposta di jmoreno, è possibile negare a un utente l'accesso a tutto tranne le autorizzazioni EXECUTE sulle procedure memorizzate, quindi sfruttare il concatenamento della proprietà per fare in modo che la procedura memorizzata esegua le operazioni richieste sui tavoli.

Vedi qui per i dettagli https://msdn.microsoft.com/en-us/library/bb669058(v=vs.110).aspx

Quando l'utente inserisce il proprio lato client nome utente / password, li memorizzo e invio come parametri a ogni chiamata di procedura memorizzata. È quindi possibile verificarli rispetto ai valori memorizzati in una tabella prima di eseguire l'operazione desiderata.

Sicuramente non è l'ultima parola in termini di sicurezza, ma potrebbe essere necessario se i tuoi PC hanno accessi generici, limitando la tua capacità di utilizzare gruppi AD per le autorizzazioni o se hai un accesso limitato a AD stesso.


2

Un approccio consiste nell'utilizzare i gruppi di annunci pubblicitari e le procedure memorizzate per limitare ciò che l'utente può fare, ad esempio il DB del foglio presenze, potrebbe consentire l'inserimento, l'aggiornamento e l'eliminazione delle ore degli utenti, ma non consentire l'aggiornamento delle ore di qualcun altro. L'ID dell'utente verrebbe fornito dal motore DB, l'utente non avrebbe accesso diretto alle tabelle DB, ma solo agli sp che eseguivano query in base al proprio ID di accesso.

Naturalmente questo non è sempre fattibile, ma può esserlo. L'approccio migliore dipenderà dalle vostre esigenze e risorse.


Questo è qualcosa che non avevo considerato. Non sono sicuro che sia perfetto, ma funzionerebbe.
Scott Whitlock,

1

Quello che accenni a "servizio web" si chiama architettura di livello n . È generalmente la strada da percorrere nei casi in cui sono probabili problemi di sicurezza o di configurazione (ad esempio, la distribuzione di un'applicazione in molti uffici). Tuttavia, non deve essere "basato sul Web". Molti lavorano con altri protocolli.

Si crea un server delle applicazioni che funge da intermediario tra il client e il database (e altre risorse). Il server delle applicazioni gestisce l'autenticazione basata sull'applicazione ed esegue azioni per conto del client. In effetti, idealmente non dovresti fare alcun SQL nel tuo client, ma piuttosto chiamare metodi sul server delle app. Il server delle applicazioni gestirà tutta la manipolazione dei dati.

C'è un certo numero di vantaggi nell'approccio. Non è necessario configurare connessioni al database e driver sui client. Non si memorizzano utenti, password e server del database. La configurazione dei client non è nemmeno necessaria: basta indicarli nel codice all'URL o all'indirizzo corretti. Inoltre, con la "logica" nel server delle applicazioni, non è necessario ripetere se stessi durante lo sviluppo di altre applicazioni: lo stesso server delle app può essere riutilizzato da diversi tipi di client.


Ancora meglio, se (o quando) qualcuno hackera i tuoi desktop (o server web in un equivalente basato sul web), l'attaccante potrebbe avere pieno accesso al sistema operativo, ma non ha ancora accesso al DB. Quindi non possono quindi eseguire "select * from users" inoltrato a un file che portano via, si rompono a loro piacimento e lasciano che il tuo CEO spieghi ai media perché il tuo sistema sicuro è stato compromesso. Se si utilizza anche sprocs sul DB che consente solo di eseguire l'accesso, allora l'attaccante può incidere il vostro app sever troppo e ancora non è possibile ottenere l'intero database degli utenti.
gbjbaanb,

1

La tecnologia è cambiata un po '. Se si autentica ciascun utente nel database stesso e si utilizzano i ruoli del database, è ora possibile utilizzare quella che viene chiamata vista aggiornabile per risolvere questo problema, almeno in SQL Server.

Ecco come potrebbe apparire una vista aggiornabile per una tabella chiamata in SomeTablecui ogni riga in quella tabella è collegata a un dipendente. Il dipendente dovrebbe essere in grado di vedere le righe collegate a loro e i membri del ruolo HR dovrebbero essere in grado di vedere tutte le righe, ad esempio:

CREATE VIEW [dbo].[vwSomeTable]
AS
    SELECT SomeTable.*
    FROM SomeTable
        INNER JOIN Employee ON SomeTable.Employee_ID = Employee.Employee_ID
    WHERE Employee.Username = USER_NAME() OR IS_MEMBER('HR_Role')=1

GO

Quindi quello che fai è dare autorizzazioni di lettura (e possibilmente scrittura) sulla vista ( vwSomeTable) a tutti gli utenti, e non dare autorizzazioni sulla tabella ( SomeTable).

Puoi testarlo in questo modo:

EXECUTE AS USER = 'Some_Regular_Username'
SELECT * FROM vwSomeTable

... che dovrebbe restituire solo le loro righe. O:

EXECUTE AS USER = 'Some_HR_Username'
SELECT * FROM vwSomeTable

... che restituirà tutte le righe. Tieni presente che per eseguire questo test avrai bisogno delle autorizzazioni di esecuzione come (rappresentazione).

Le viste sono aggiornabili, quindi anche l'utente normale può farlo, purché la riga sia collegata alla propria Employeeriga:

UPDATE vwSomeTable
SET SomeColumn = 5
WHERE SomeTable_ID = 'TheID'

0

L'uso dell'autenticazione basata su certificato è il modo "corretto" di implementare un account sql condiviso. L'obiettivo è eliminare l'uso della password per questo tipo di cose.

Aggiornare:

Suppongo che abbia frainteso la domanda. Ho pensato che avesse a che fare con il tentativo di trovare un'alternativa al mettere un nome utente e una password db in una configurazione dell'applicazione, o nel backup dell'applicazione stessa.

È possibile eliminare il problema della gestione delle password nelle applicazioni utilizzando invece i certificati lato client. Il certificato stesso non è abbastanza, devi avere un sistema di distribuzione e gestione in grado di eseguire operazioni come la revoca del certificato.

Riferimento: http://en.wikipedia.org/wiki/Public-key_infrastructure


Puoi fornire qualche informazione in più su questo? Sembra che potrebbe essere ortogonale all'intento della mia domanda originale, ma è interessante.
Scott Whitlock,

0

Costruendo una nuova soluzione di sicurezza desktop, abbiamo optato per la soluzione di servizi Web che proverò a descrivere qui sotto.

Compiliamo gli eseguibili delle applicazioni desktop in un ambiente separato dagli sviluppatori. E calcola un HASH da quel file eseguibile che è registrato nel database.

Un servizio Web che fornisce tutte le informazioni necessarie per l'esecuzione dell'applicazione, la password del DB, le informazioni sulla stringa di connessione, le autorizzazioni utente, ecc ...

utilizziamo l'accesso con DB singolo per applicazione e registriamo i dettagli dell'utente nel database nelle variabili di sessione per poter controllare i record.

Una DLL gestisce tutte le comunicazioni dall'applicazione desktop al servizio Web, accessibile solo con un token compilato nella DLL.

Per poter ottenere la password del DB dell'applicazione dal servizio Web, la DLL calcola l'HASH dei chiamanti DLL in fase di runtime e passa come parametro al servizio Web che convalida il token DLL e il runtime eseguibile ha calcolato l'HASH a quello registrato al momento della distribuzione (l'applicazione è disponibile solo in un'unica installazione condivisa in rete).

In questo modo siamo riusciti a risolvere il problema di sicurezza di cui ci occupavamo di più e siamo consapevoli di alcuni difetti di progettazione. Stanno quasi finendo questa implementazione e finora siamo contenti dei risultati.

Modifica: è possibile sostituire l'idea dell'hash utilizzando firme digitali e certificati X.509.


1
Sembra abbastanza ovvio dove si trova il buco di sicurezza evidente. La DLL di cui parli si trova sul sistema del client e non c'è modo per il tuo codice server di verificare che stia parlando con una copia legittima della DLL o con una hackerata / dannosa / falsa. Hai appena creato un sacco di lavoro per te stesso senza aggiungere molta, se del caso, ulteriore sicurezza. Tutto ciò di cui una persona malintenzionata ha bisogno è il token e l'algoritmo, entrambi presenti nella DLL per chiunque voglia cercare.
Scott Whitlock,

@ScottWhitlock, Sì, sono d'accordo. stiamo cercando di offuscare la DLL e il traffico che passa su HTTPS. Stiamo cercando di migliorare, mi piacerebbe davvero qualsiasi input su come migliorarlo. Ma questa soluzione risolve già molti problemi del sistema attuale, comprese le password in testo semplice archiviate nei file di rete. Inoltre il servizio web consente di riutilizzare un sacco di codice accessibile da qualsiasi lingua client che utilizziamo qui, compresi i client Delphi e Clipper (Harbour)!
Vitor Arbex,

Nel tuo sistema, l'utente accede ed è presumibilmente autenticato dal servizio web. Supponendo l'uso di HTTPS, non è abbastanza buono? Non devi fidarti del software client, poiché sai che l'utente è quello che dicono di essere e controlli il servizio web, quindi assicurati che il servizio web distribuisca solo le informazioni che l'utente in questione è autorizzato a vedere. Anche se hanno retroingegnerizzato il cliente e scritto il proprio, che danno potrebbero fare? Solo il tuo servizio web conosce la password del DB e questo dovrebbe essere sicuro.
Scott Whitlock,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.