Stringa identificativa sequenziale che non può essere decodificata (il problema del "numero di fattura")

53

Diciamo che gestisco un sito web dove puoi creare immagini di gatti. Fornisco ad ogni immagine di gatto un identificatore univoco in modo che possa essere condivisa sui social media con http://catpictures.com/base62Identifier .

Potrei dare al gatto immagini identificatori sequenziali come 1,2,3, ecc., ma poi sarebbe possibile scoprire facilmente quante nuove immagini di gatti create dagli utenti al giorno (dall'identificatore più grande che restituisce ogni 200 HTTP giorno). Questo mi espone alla strategia comune di ordinare un prodotto dalla concorrenza una volta al mese e prendendo nota del numero della fattura. I dati sul traffico del sito web sono ben correlati alle entrate aziendali, quindi ovviamente voglio mantenere segrete queste informazioni.

Quello che sto considerando di provare:

Sembra un lavoro per un algoritmo di hash, giusto? Il problema è che osservando un hash è abbastanza facile dire quale algoritmo lo ha creato (md5, crc32, ecc.). Qualcuno con un tavolo arcobaleno avrebbe fatto un lavoro breve a quell'idea. Potrei salare l'identificatore [hash ("sale" +1), hash ("sale" +2), ...], ma poi dovrei preoccuparmi della sicurezza associata al sale. E controllo delle collisioni.

Un'altra idea che ho avuto è stata quella di generare una stringa casuale di caratteri e usarla come chiave primaria dell'immagine del gatto nel database (o solo avrei potuto cancellare i primi n bit dei dati delle immagini cat). In questo modo dovrei solo controllare le collisioni.

Esiste un modo standard e pratico per evitare di esporre i tuoi volumi di traffico attraverso i tuoi URL identificatori univoci?

Modifica: sono specificamente alla ricerca di una soluzione che sia una buona combinazione di sicurezza e idoneità come chiave primaria del database o colonna indicizzabile.

    
posta Escher 13.12.2015 - 17:07
fonte

13 risposte

79

L'approccio standard a questo tipo di problema è creare un UUID (Universally Unique Identifier) per ogni immagine. Questo è generalmente un identificatore casuale a 128 bit che è possibile assegnare a ciascuna immagine senza particolare preoccupazione che sarebbe possibile enumerare le immagini tramite un attacco a forza bruta nello spazio dei nomi.

Ad esempio in .NET è possibile utilizzare il GUID struttura per questo tipo di scopo. Da Windows 2000 ( source ), Guid.NewGuid genera UUID casuale (versione 4). (Le versioni precedenti hanno generato un UUID versione 1 che rivela la data in cui è stato generato , non fare nulla per proteggerti dal problema "numero di fattura".)

    
risposta data 13.12.2015 - 17:52
fonte
30

Vorrei semplicemente usare l'hash dell'immagine. Qual è il problema con qualcuno che ha scoperto l'hash che hai usato? Se penso che "questa parte dell'url si presenta come una sha1", scarica il file e ha che sha1, avevo ragione. Ma questo non mi rende in grado di rompere la tua «sicurezza del gatto». Anche se fosse possibile tentare di rompere l'hash per capire l'immagine, non ha senso tentare quello invece di scaricarlo semplicemente.

    
risposta data 13.12.2015 - 21:07
fonte
14

Basta generare un hash crittograficamente sicuro dei dati dell'immagine e usarlo come identificativo.

Questo ha due effetti collaterali:

  • Le persone possono sapere se un'immagine esiste già nel tuo servizio chiedendo un'immagine con quell'hash.
  • Le persone non possono caricare immagini duplicate.

Entrambi questi effetti non sono intrinsecamente cattivi. Potrebbero anche tornare utili. Ma se vuoi evitarli, puoi salare ogni hash dell'immagine con un numero pseudocasuale da un generatore di numeri casuali sicuro.

Le collisioni non sono nulla di cui preoccuparsi, comunque. Con una funzione hash come SHA256, il le probabilità di una collisione casuale sono così astronomicamente piccole, sarebbe una sensazione quando ne troverebbero una .

    
risposta data 13.12.2015 - 18:09
fonte
9

Il modo standard consiste semplicemente nel generare in modo casuale i tuoi URL, utilizzando un generatore di numeri pseudo-casuali crittograficamente sicuro (CSPRNG).

Nessun bisogno di hashing o simili - basta usare semplici numeri casuali. Non è necessario che siano GUID (a meno che il database non gestisca i GUID meglio dei numeri semplici per qualche motivo). Presumibilmente, il tuo sito ricorda già quale immagine è accessibile a ogni URL, quindi modificalo per gestire gli URL casuali anziché quelli sequenziali.

Un numero casuale a 128 bit dovrebbe essere abbastanza lungo.

Ricorda di verificare la presenza di URL duplicati durante l'elaborazione di nuove immagini.

    
risposta data 13.12.2015 - 22:33
fonte
8

Da ciò che ho letto nella domanda, nei commenti e in altre risposte, tutto sta girando alla ricerca di un identificatore univoco per ogni immagine, che non è ipotizzabile, né fornirebbe informazioni sul numero di immagini e facile da gestire in un banca dati.

Quindi, perché non usi semplicemente il timestamp di inserimento (numero di millisecondi dal 1970)? Se c'è una probabilità che due persone inseriscano un'immagine di gatto nello stesso millisecondo, puoi concatenarlo con un numero sequenziale corrispondente al numero di inserimento in quel millisecondo.

In questo modo, l'unica cosa in cui qualcuno che cerca aggressivamente la tua ultima foto potrebbe scoprire è l'ultima volta che qualcuno ha aggiunto una foto, a patto che tu abbia fatto fare a un tale cretino quello che sarebbe sembrato un attacco giornaliero.

Nel frattempo non avresti problemi con le collisioni o il supporto del database.

    
risposta data 15.12.2015 - 10:52
fonte
6

Soluzione alternativa:

Aggiungi metadati ai tuoi identificatori di immagine. Esempio:

philipp_20151213_00002.jpg - Seconda immagine postata dall'utente Philipp il 13 dicembre 2015.

Rilevo i metadati, ma sono solo i dati che un utente può vedere quando si fa clic su quel link (presumo).

Questo non dice a un osservatore quante immagini sono pubblicate in totale sul tuo servizio, solo sull'attività di quel particolare utente in quel particolare giorno. Se vuoi nascondere anche questo, potresti usare numeri pseudocasuali invece di numeri sequenziali. Le collisioni potrebbero essere ancora possibili quando un singolo utente carica una grande quantità di immagini in un giorno, ma sarà abbastanza raro da poterle gestire semplicemente generando nuovi numeri casuali fino a quando non ne hai uno che non viene preso.

    
risposta data 13.12.2015 - 18:22
fonte
1

Ecco un metodo. Conserva un CSPRNG da 8 byte a livello di server. Quindi, per ciascuna nuova immagine, generare un altro CSPRNG da 8 byte. Hash questo CSPRNG con il tuo CSPRNG a livello di server (md5 va bene). Quindi XOR gli ultimi 8 byte dell'hash con l'ID immagine (che verrà incrementato automaticamente da 0 in un database). Il client riceverà una codifica Base64 del CSPRNG a 8 byte univoco dell'immagine insieme al risultato XOR a 8 byte. Questo sarà l'ID dell'immagine pubblica.

Quando il server riceve l'ID immagine pubblico, eseguirà l'hash dei primi 8 byte dell'ID pubblico insieme al CSPRNG da 8 byte a livello di server. Quindi prenderà gli ultimi 8 byte dell'hash e XOR con gli ultimi 8 byte dell'ID pubblico. Il risultato sarebbe l'ID interno privato che può essere indicizzato dal database.

Aggiornamento (spiegazione):

Innanzitutto, pre-definire un CSPRNG globale casuale che verrà utilizzato per tutti i calcoli ID (8 byte o 64 bit con 18.446.744.073,709,551,616 combinazioni possibili).

serverCSPRNG = CSPRNG(8)

Per creare un nuovo ID pubblico (16 byte) da un privateID (8 byte), effettuare le seguenti operazioni:

newCSPRNG = CSPRNG(8)
hashEnding = last8Bytes(md5(newCSPRNG + serverCSPRNG))
publicID = newCSPRNG + XOR(hashEnding, privateID)

Per derivare il privateID dal publicID:

hashEnding = last8Bytes(md5(first8Bytes(publicID) + serverCSPRNG))
privateID = XOR(hashEnding, last8Bytes(publicID))

Per ulteriore sicurezza, un CSPRNG secondario (statico solo server) può essere XOR'd sugli ultimi 8 byte del publicID per proteggerlo completamente dagli attacchi brute-force (poiché implementa il modello di sicurezza inerente a un one-time-pad).

    
risposta data 13.12.2015 - 17:55
fonte
1

Come notato qui : Hash, UUID, ecc. hanno lo "svantaggio" che gli inserimenti di record nel DB in cui questi hash / uuid sono PK e PK sono in cluster sono probabilmente molto costosi (definiscono costosi ...) poiché di solito non sono sequenziali (a meno che non venga utilizzata una funzione specifica come NEWSEQUENTIALID , tuttavia: nota il blocco "importante" in quella pagina: " Se la privacy è un problema, non usare questa funzione. È possibile indovinare il valore del prossimo GUID generato ... ").

Oltre ai suggerimenti qui prenderei in considerazione qualcosa come Twitter ( fuori produzione ) fiocco di neve . Ho scritto una libreria .Net simile ( IdGen ); è readme ha alcune informazioni su come funziona esattamente. Il vantaggio è che gli ID generati sono ancora (per lo più) sequenziali, non troppo intensivi (64 bit contro 128 UUID / hash) e possono essere utilizzati in un ambiente distribuito (non coordinato) in cui vi sono diversi host / processi che generano ID senza causare collisioni. E anche se sono sequenziali, non danno molte informazioni sul numero di immagini di gatti (o, più in generale, sul numero di "ID usati") per un certo periodo di tempo.

    
risposta data 16.12.2015 - 16:02
fonte
1

This sounds like a job for a hashing algorithm, right?

No, perché mentre osservi devi preoccuparti delle collisioni. Per me sembra un lavoro per una permutazione, cioè un codice a blocchi. Ciò richiede la gestione di una chiave, che è il rovescio della medaglia, ma ti consente di utilizzare la funzione di auto-incremento del tuo database e di non preoccuparti delle collisioni.

La parte difficile è decidere cosa fare per la flebo, e qui ci sono opzioni. Potresti generarne uno nuovo ogni volta che crei un URL, quindi ci saranno potenzialmente ad es. 2 ^ 128 URL diversi per immagine di gatto. Si potrebbe fare in modo che l'IV sia per utente o per sessione e memorizzato sul lato server come parte dello stato del profilo utente / sessione. Potresti persino renderlo per utente, ma incluso nell'URL, in modo da poter tenere traccia di chi riesce a rendere virali le immagini.

    
risposta data 16.12.2015 - 18:00
fonte
0

Un approccio consiste nell'usare hashids .

Hashids is a small open-source library that generates short, unique, non-sequential ids from numbers.

It converts numbers like 347 into strings like “yr8”, or array of numbers like [27, 986] into “3kTMd”.

You can also decode those ids back. This is useful in bundling several parameters into one or simply using them as short UIDs.

Le prestazioni del DB non sono compromesse in quanto è possibile continuare a utilizzare internamente ID numerici sequenziali. Nel frattempo le chiavi esterne sono opache.

    
risposta data 14.12.2015 - 18:29
fonte
0

Ho una soluzione a bassa tecnologia per questo problema. Utilizza semplicemente un servizio di abbreviazione URL o scrivi il tuo.

Fornisce quanto segue:

  1. L'URL pubblico non è esposto sui siti dei social media.
  2. I tuoi URL sono garantiti in modo casuale e arbitrario.
  3. Sei libero di modificare l'implementazione sottostante della denominazione delle risorse e i collegamenti esterni continueranno a funzionare.
  4. Condivisione più semplice http://catpic.to/i34dhY rispetto a http://catpictures.com/some-guid-string .
  5. L'ID univoco è facilmente indicizzato / cercato.

Se non vuoi fare affidamento su un servizio di terze parti, puoi eseguire facilmente il rollover implementando una funzione biettiva nella lingua prescelta.

    
risposta data 16.12.2015 - 07:54
fonte
0

Problema:

  • Vogliamo avere un numero che sia sequenziale; altrimenti diventa costoso aggiungere record al database poiché la metà degli indici deve essere aggiornata in ordine prevalentemente casuale.
  • Non vogliamo che il numero si riferisca al numero di gatti che sono stati caricati.
  • Abbiamo bisogno che il numero sia unico ma solo all'interno del tuo sito web.

Quindi:

  • nextCat è impostato su 0 quando viene avviato il sito web first , sarà probabilmente necessario 64 bit.
  • nextCat è incremented ogni volta che viene aggiunto un gatto e newCat è impostato su true .
  • nextCat è incremented da un timer casuale che si attiva a una velocità che è più veloce di quanto ci si aspetti dai gatti. Tuttavia se newCat è true , allora l'incremento non viene eseguito per questo fuoco timer e newCat è impostato su false .
  • ogni gatto è ANCHE dato un GUID, ma non deve mai essere trovato in base al suo GUID
  • l'indirizzo web per un gatto è qualcosa di divertente / gatti / numero-numero-gatto /
  • se quando viene richiesto un gatto la catGuid è sbagliata, viene data la stessa risposta per un numero di gatto che non si riferisce a un gatto.

(Il timer è fatto per un tempo casuale, quindi è difficile dire se due gatti vengono aggiunti tra un incendio del timer.)

    
risposta data 16.12.2015 - 16:49
fonte
-2

Best practice generale: non esporre mai il PKEY a nessun link web.

Nel tuo database - la tua PKEY deve essere un BIGINT per la velocità. Inoltre, nel tuo database, considera l'aggiunta di questo campo ... ( public_filename ..if non esiste) alla tua tabella. Il campo public_filename deve essere una stringa guid. Utilizza una funzione guid per rinominare il file con un nome file univoco al momento del caricamento sul tuo server e popola public_filename con quello.

Il public_filename dovrebbe essere usato per i link, non per il PKEY.

Inoltre, ti consiglio di conservare un campo user_filename per supportare qualsiasi ricerca legale dall'uploader, se lo consenti. user_filename sarebbe il nome file originale caricato dall'utente.

Non esporre mai il PKEY a nessun link web, usa sempre qualche forma di public_filename . Utilizza le query del database per de-fare riferimento a public_filename a un PKEY e da lì puoi capire quale file pubblicare dal server.

Un'altra best practice: non sovrascrivere mai automaticamente il caricamento di un file dell'utente. Rinominare il campo user_filename con una serializzazione (-001, -002).

Le probabilità sono che otterrai molti file chiamati "mycat" dallo stesso utente.

    
risposta data 13.12.2015 - 21:04
fonte

Leggi altre domande sui tag