Domanda

Cosa significa autenticazione RESTful e come funziona? Non riesco a trovare una buona panoramica su Google. La mia unica comprensione è che passi la chiave di sessione (remeberal) nell'URL, ma questo potrebbe essere terribilmente sbagliato.

È stato utile?

Soluzione

Come gestire l'autenticazione in un'architettura Client-Server RESTful è una questione di dibattito.

Comunemente, può essere realizzato, nel mondo SOA su HTTP tramite:

  • Autenticazione di base HTTP su HTTPS;
  • Gestione dei cookie e delle sessioni;
  • Token nelle intestazioni HTTP (ad esempio OAuth 2.0 + JWT);
  • Autenticazione della query con parametri di firma aggiuntivi.

Dovrai adattare, o ancor meglio mescolare quelle tecniche, per abbinare al meglio la tua architettura software.

Ogni schema di autenticazione ha i propri PRO e CON, a seconda dello scopo della politica di sicurezza e dell'architettura software.

Autenticazione HTTP di base su HTTPS

Questa prima soluzione, basata sul protocollo HTTPS standard, è utilizzata dalla maggior parte dei servizi Web.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

È facile da implementare, disponibile per impostazione predefinita su tutti i browser, ma presenta alcuni inconvenienti noti, come la terribile finestra di autenticazione visualizzata sul browser, che persisterà (non esiste alcuna funzionalità simile a LogOut qui), alcune aggiuntive sul lato server Consumo di CPU e il fatto che il nome utente e la password siano trasmessi (tramite HTTPS) al Server (dovrebbe essere più sicuro lasciare che la password rimanga solo sul lato client, durante l'immissione da tastiera, e sia memorizzata come hash sicuro su il server).

Possiamo utilizzare Autenticazione digest , ma richiede anche HTTPS, poiché è vulnerabile a < a href = "http://en.wikipedia.org/wiki/Man-in-the-middle_attack" rel = "noreferrer"> MiM o Replay attacchi, ed è specifico per HTTP.

Sessione tramite cookie

Ad essere onesti, una sessione gestita sul Server non è veramente Stateless.

Una possibilità potrebbe essere quella di conservare tutti i dati all'interno del contenuto dei cookie. E, in base alla progettazione, il cookie viene gestito dal lato server (il client, infatti, non tenta nemmeno di interpretare questi dati dei cookie: li restituisce al server solo ad ogni richiesta successiva). Ma questi dati sui cookie sono dati sullo stato dell'applicazione, quindi il client dovrebbe gestirli, non il server, in un puro mondo Stateless.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

La stessa tecnica dei cookie è collegata a HTTP, quindi non è veramente RESTful, che dovrebbe essere indipendente dal protocollo, IMHO. È vulnerabile a MiM o Replay attacchi.

Concesso tramite token (OAuth2)

Un'alternativa è quella di inserire un token nelle intestazioni HTTP in modo che la richiesta sia autenticata. Questo è ciò che fa OAuth 2.0, ad esempio. Vedi RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

In breve, è molto simile a un cookie e presenta gli stessi problemi: non stateless, basandosi sui dettagli di trasmissione HTTP e soggetto a molte debolezze di sicurezza - inclusi MiM e Replay - quindi deve essere usato solo su HTTPS. In genere, un JWT viene utilizzato come token.

Autenticazione query

L'autenticazione della query consiste nel firmare ogni richiesta RESTful tramite alcuni parametri aggiuntivi sull'URI. Vedi questo articolo di riferimento .

È stato definito come tale in questo articolo:

  

Tutte le query REST devono essere autenticate firmando i parametri della query   ordinati in ordine alfabetico minuscolo utilizzando la credenziale privata   come token di firma. La firma dovrebbe avvenire prima della codifica dell'URL   stringa di query.

Questa tecnica è forse la più compatibile con uno Stateles

Altri suggerimenti

Dubito che le persone gridino con entusiasmo "Autenticazione HTTP" mai provato a creare un'applicazione basata su browser (anziché un servizio web da macchina a macchina) con REST (nessuna offesa intesa - non credo proprio che abbiano mai affrontato le complicazioni).

I problemi che ho riscontrato con l'utilizzo dell'autenticazione HTTP su servizi RESTful che producono pagine HTML da visualizzare in un browser sono:

  • l'utente in genere ottiene una brutta casella di accesso creata dal browser, che è molto ostile per l'utente. non è possibile aggiungere recupero password, caselle di aiuto, eccetera.
  • disconnettersi o accedere con un nome diverso è un problema: i browser continueranno a inviare informazioni di autenticazione al sito fino alla chiusura della finestra
  • i timeout sono difficili

Un articolo molto approfondito che affronta questi punti per punto è qui , ma questi risultati in un lotto di hacker javascript specifici del browser, soluzioni alternative per soluzioni alternative, eccetera. In quanto tale, inoltre, non è compatibile con le versioni successive, pertanto richiederà una manutenzione costante poiché vengono rilasciati nuovi browser. Non considero quel design pulito e chiaro, inoltre sento che c'è molto lavoro extra e mal di testa solo per poter mostrare con entusiasmo il mio badge REST ai miei amici.

Credo che i cookie siano la soluzione. Ma aspetta, i biscotti sono cattivi, vero? No, non lo sono, il modo in cui i cookie vengono spesso utilizzati è malvagio. Un cookie stesso è solo una parte delle informazioni sul lato client, proprio come le informazioni di autenticazione HTTP che il browser terrà traccia durante la navigazione. E questa informazione sul lato client viene inviata al server ad ogni richiesta, proprio come le informazioni di autenticazione HTTP. Concettualmente, l'unica differenza è che il contenuto di questo stato del lato client può essere determinato dal server come parte della sua risposta.

Rendendo le sessioni una risorsa RESTful con solo le seguenti regole:

  • Una sessione mappa una chiave per un ID utente (e possibilmente un timestamp last-action per i timeout)
  • Se esiste una sessione , significa che la chiave è valida.
  • Accesso significa POSTARE / sessioni, una nuova chiave è impostata come cookie
  • Logout significa ELIMINAZIONE / sessioni / {chiave} (con il POST sovraccarico, ricorda, siamo un browser e HTML 5 è ancora una lunga strada da percorrere)
  • L'autenticazione viene effettuata inviando la chiave come cookie ad ogni richiesta e verificando se la sessione esiste e è valida

L'unica differenza con l'autenticazione HTTP, ora, è che la chiave di autenticazione viene generata dal server e inviata al client che continua a rispedirla, anziché al client che la calcola dalle credenziali immesse.

converter42 aggiunge che quando si utilizza https (che dovremmo), è importante che il cookie abbia il suo flag di sicurezza impostato in modo che le informazioni di autenticazione non vengano mai inviate su una connessione non sicura. Ottimo punto, non l'avevo visto da solo.

Sento che questa è una soluzione sufficiente che funziona bene, ma devo ammettere che non sono abbastanza esperto di sicurezza per identificare potenziali buchi in questo schema - tutto quello che so è che centinaia di applicazioni Web non RESTful usano essenzialmente lo stesso protocollo di accesso ($ _SESSION in PHP, HttpSession in Java EE, ecc.). I contenuti dell'intestazione del cookie vengono semplicemente utilizzati per indirizzare una risorsa lato server, proprio come una lingua di accettazione potrebbe essere utilizzata per accedere alle risorse di traduzione, eccetera. Sento che è lo stesso, ma forse altri no? Cosa ne pensate, ragazzi?

Su questo argomento è già stato detto abbastanza da brave persone qui. Ma ecco i miei 2 centesimi.

Esistono 2 modalità di interazione:

  1. uomo-macchina (HTM)
  2. machine-to-machine (MTM)

La macchina è il comune denominatore, espresso come API REST, e gli attori / clienti sono gli umani o le macchine.

Ora, in un'architettura veramente RESTful, il concetto di apolidia implica che tutti gli stati applicativi rilevanti (ovvero gli stati lato client) devono essere forniti con ogni richiesta. Per pertinente, si intende che tutto ciò che è richiesto dall'API REST per elaborare la richiesta e fornire una risposta appropriata.

Quando lo consideriamo nel contesto di applicazioni da uomo a macchina, "basato su browser" come Skrebbel sottolinea sopra, ciò significa che l'applicazione (web) in esecuzione nel browser dovrà inviare il suo stato e le informazioni pertinenti con ogni richiesta che fa alle API REST back-end.

Considera questo: hai una piattaforma dati / informazioni esposta asset di API REST. Forse hai una piattaforma BI self-service che gestisce tutti i cubi di dati. Ma vuoi che i tuoi (umani) clienti accedano a questo tramite (1) app web, (2) app mobile e (3) alcune applicazioni di terze parti. Alla fine, anche la catena di MTM porta a HTM - giusto. Pertanto, gli utenti umani rimangono all'apice della catena di informazione.

Nei primi 2 casi, hai un caso per l'interazione uomo-macchina, le informazioni vengono effettivamente consumate da un utente umano. Nell'ultimo caso, hai un programma macchina che utilizza le API REST.

Il concetto di autenticazione si applica a tutti i livelli. Come lo progetterai in modo tale che le tue API REST siano accessibili in modo uniforme e sicuro? Per come la vedo io, ci sono 2 modi:

Way-1:

  1. Non c'è accesso, tanto per cominciare. Ogni richiesta esegue l'accesso
  2. Il client invia i suoi parametri identificativi + la richiesta specifica parametri con ogni richiesta
  3. L'API REST li prende, si gira, esegue il ping dell'archivio utenti (qualunque cosa sia) e conferma l'autent
  4. Se l'autenticazione è stabilita, soddisfa la richiesta; altrimenti, nega con il codice di stato HTTP appropriato
  5. Ripeti quanto sopra per ogni richiesta in tutte le API REST nel tuo catalogo

Way-2:

  1. Il client inizia con una richiesta di autenticazione
  2. Un'API REST di accesso gestirà tutte queste richieste
  3. Comprende i parametri di autenticazione (chiave API, uid / pwd o qualunque altra cosa scegliere) e verifica l'autenticità rispetto all'archivio utenti (LDAP, AD, MySQL DB ecc.)
  4. Se verificato, crea un token di autenticazione e lo restituisce al file client / chiamante
  5. Il chiamante invia quindi questo token di autenticazione + richiede parametri specifici con ogni successiva richiesta ad altre API REST aziendali, fino alla disconnessione o fino alla scadenza del contratto di locazione

Chiaramente, in Way-2, le API REST avranno bisogno di un modo per riconoscere e fidarsi del token come valido. L'API di accesso ha eseguito la verifica dell'autenticazione e pertanto quella "chiave di parcheggio". deve essere considerato attendibile da altre API REST nel tuo catalogo.

Questo, ovviamente, significa che la chiave / token di autenticazione dovrà essere archiviata e condivisa tra le API REST. Questo repository token condiviso e attendibile può essere locale / federato qualunque, consentendo alle API REST di altre organizzazioni di fidarsi l'una dell'altra.

Ma sto divagando.

Il punto è un "stato" (sullo stato autenticato del client) deve essere mantenuto e condiviso in modo che tutte le API REST possano creare un cerchio di fiducia. Se non lo facciamo, che è il Way-1, dobbiamo accettare che un atto di autenticazione debba essere eseguito per qualsiasi / tutte le richieste in arrivo.

L'esecuzione dell'autenticazione è un processo che richiede molte risorse. Immagina di eseguire query SQL, per ogni richiesta in arrivo, contro il tuo archivio utenti per verificare la corrispondenza uid / pwd. Oppure, per crittografare ed eseguire hash matche

Ecco una soluzione di autenticazione veramente e completamente RESTful:

  1. Crea una coppia di chiavi pubblica / privata sul server di autenticazione.
  2. Distribuisci la chiave pubblica su tutti i server.
  3. Quando un client esegue l'autenticazione:

    3.1. emettere un token che contiene quanto segue:

    • Scadenza
    • nome utente (facoltativo)
    • IP utenti (opzionale)
    • hash di una password (opzionale)

    3.2. Crittografa il token con la chiave privata.

    3.3. Invia il token crittografato di nuovo all'utente.

  4. Quando l'utente accede a qualsiasi API deve anche passare il proprio token di autenticazione.

  5. I server possono verificare che il token sia valido decodificandolo mediante la chiave pubblica del server di autenticazione.

Questa è l'autenticazione stateless / RESTful.

Nota che se fosse incluso un hash della password, l'utente avrebbe anche inviato la password non crittografata insieme al token di autenticazione. Il server ha potuto verificare che la password corrispondesse alla password utilizzata per creare il token di autenticazione confrontando gli hash. Sarebbe necessaria una connessione sicura usando qualcosa come HTTPS. Javascript sul lato client potrebbe gestire il recupero della password dell'utente e la sua memorizzazione sul lato client, sia in memoria che in un cookie, eventualmente crittografato con la chiave pubblica del server.

Ad essere sincero con te ho visto grandi risposte qui, ma qualcosa che mi preoccupa un po 'è quando qualcuno porterà il concetto di apolide a un estremo dove diventa dogmatico. Mi ricorda quei vecchi fan di Smalltalk che volevano solo abbracciare OO puro e se qualcosa non è un oggetto, allora stai sbagliando. Dammi una pausa.

L'approccio RESTful dovrebbe semplificarti la vita e ridurre il sovraccarico e il costo delle sessioni, provare a seguirlo perché è una cosa saggia da fare, ma nel momento in cui segui una disciplina (qualsiasi disciplina / linea guida) al estremo dove non offre più il vantaggio a cui era destinato, quindi lo stai facendo male. Alcuni dei migliori linguaggi oggi hanno sia la programmazione funzionale che l'orientamento agli oggetti.

Se il modo più semplice per risolvere il tuo problema è archiviare la chiave di autenticazione in un cookie e inviarla sull'intestazione HTTP, allora fallo, non abusarne. Ricorda che le sessioni sono cattive quando diventano pesanti e grandi, se tutta la tua sessione è composta da una breve stringa contenente una chiave, qual è il grosso problema?

Sono aperto ad accettare correzioni nei commenti, ma non vedo il punto (finora) di rendere miserabili le nostre vite per evitare semplicemente di tenere un grande dizionario di hash nel nostro server.

Innanzitutto, un servizio Web RESTful è STATELESS (o in altre parole, SESSIONLESS ). Pertanto, un servizio RESTful non ha e non dovrebbe avere un concetto di sessione o cookie coinvolti. Il modo per eseguire l'autenticazione o l'autorizzazione nel servizio RESTful è utilizzare l'intestazione Autorizzazione HTTP come definito nelle specifiche HTTP RFC 2616. Ogni singola richiesta deve contenere l'intestazione di autorizzazione HTTP e la richiesta deve essere inviata tramite una connessione HTTP (SSL). Questo è il modo corretto per eseguire l'autenticazione e verificare l'autorizzazione delle richieste in un servizio Web HTTP RESTful. Ho implementato un servizio Web RESTful per l'applicazione Cisco PRIME Performance Manager presso Cisco Systems. E come parte di quel servizio web, ho implementato anche l'autenticazione / autorizzazione.

Rubens Gomes.

Non si tratta certamente di " chiavi di sessione " poiché viene generalmente utilizzato per fare riferimento all'autenticazione senza sessioni eseguita all'interno di tutti i vincoli di REST. Ogni richiesta è auto-descrittiva e contiene informazioni sufficienti per autorizzare la richiesta da sola senza alcuno stato dell'applicazione sul lato server.

Il modo più semplice per affrontarlo è iniziare con i meccanismi di autenticazione integrati di HTTP in RFC 2617 .

L'articolo "molto approfondito" menzionato da @skrebel ( http://www.berenddeboer.net /rest/authentication.html ) discute un metodo di autenticazione contorto ma veramente rotto.

Puoi provare a visitare la pagina (che dovrebbe essere visibile solo all'utente autenticato) http://www.berenddeboer.net/rest/site/authenticated.html senza credenziali di accesso.

(Mi dispiace non posso commentare la risposta.)

Direi che REST e autenticazione semplicemente non si mescolano. REST significa apolide ma "autenticato" è uno stato. Non puoi averli entrambi sullo stesso livello. Se sei un sostenitore di RESTful e disapprovi gli stati, allora devi andare con HTTPS (cioè lasciare il problema di sicurezza su un altro livello).

Penso che l'autenticazione riposante implichi il passaggio di un token di autenticazione come parametro nella richiesta. Esempi sono l'uso di apikeys da parte di api. Non credo che l'uso dei cookie o dell'autenticazione http sia idoneo.

Aggiornamento il 16 febbraio 2019

L'approccio menzionato in precedenza è essenzialmente "Credenziali password proprietario risorsa" tipo di concessione di OAuth2.0 . Questo è un modo semplice per iniziare. Tuttavia, con questo approccio ogni applicazione dell'organizzazione finirà con i propri meccanismi di autenticazione e autorizzazione. L'approccio raccomandato è "Codice di autorizzazione" tipo di concessione. Inoltre, nella mia risposta precedente di seguito, ho raccomandato localStorage del browser per la memorizzazione dei token di autenticazione. Tuttavia, sono arrivato a credere che i cookie siano l'opzione giusta per questo scopo. Ho dettagliato i miei motivi, l'approccio all'implementazione del tipo di concessione del codice di autorizzazione, considerazioni sulla sicurezza ecc. In questa risposta StackOverflow .


Penso che il seguente approccio possa essere utilizzato per l'autenticazione del servizio REST:

  1. Crea un'API RESTful di accesso per accettare nome utente e password per l'autenticazione. Utilizzare il metodo HTTP POST per impedire la memorizzazione nella cache e SSL per la sicurezza durante il transito Se l'autenticazione ha esito positivo, l'API restituisce due JWT: un token di accesso (validità più breve, diciamo 30 minuti) e un token di aggiornamento (validità più lunga, diciamo 24 ore)
  2. Il client (un'interfaccia utente basata sul Web) memorizza i JWT nella memoria locale e in ogni successiva chiamata API passa il token di accesso in " Autorizzazione: Bearer # token di accesso " intestazione
  3. L'API verifica la validità del token verificando la firma e la data di scadenza. Se il token è valido, controlla se l'utente (interpreta la rivendicazione "sotto" in JWT come nome utente) ha accesso all'API con una ricerca nella cache. Se l'utente è autorizzato ad accedere all'API, eseguire la logica aziendale
  4. Se il token è scaduto, l'API restituisce il codice di risposta HTTP 400
  5. Il client, alla ricezione di 400/401, richiama un'altra API REST con il token di aggiornamento in " Autorizzazione: Bearer #refresh token " intestazione per ottenere un nuovo token di accesso.
  6. Alla ricezione della chiamata con token di aggiornamento, verificare se il token di aggiornamento è valido controllando la firma e la data di scadenza. Se il token di aggiornamento è valido, aggiornare la cache dei diritti di accesso dell'utente dal DB e restituire il nuovo token di accesso e il token di aggiornamento. Se il token di aggiornamento non è valido, restituire il codice di risposta HTTP 400
  7. Se vengono restituiti un nuovo token di accesso e un token di aggiornamento, andare al passaggio 2. Se viene restituito il codice di risposta HTTP 400, il client presuppone che il token di aggiornamento sia scaduto e chiede all'utente username e password
  8. Per il logout, eliminare la memoria locale

Con questo approccio stiamo eseguendo la costosa operazione di caricamento della cache con i dettagli dei diritti di accesso specifici dell'utente ogni 30 minuti. Pertanto, se un accesso viene revocato o viene concesso un nuovo accesso, sono necessari 30 minuti per riflettere o un logout seguito da un accesso.

Questo è il modo per farlo: Utilizzo di OAuth 2.0 per l'accesso .

Puoi utilizzare altri metodi di autenticazione diversi da quelli di Google purché supportino OAuth.

Per rispondere a questa domanda dalla mia comprensione ...

Un sistema di autenticazione che utilizza REST in modo da non dover effettivamente tracciare o gestire gli utenti nel proprio sistema. Questo viene fatto usando i metodi HTTP POST, GET, PUT, DELETE. Prendiamo questi 4 metodi e li consideriamo in termini di interazione con il database come CREATE, READ, UPDATE, DELETE (ma sul web usiamo POST e GET perché questo è ciò che attualmente supporta i tag di ancoraggio). Quindi trattando POST e GET come il nostro CREATE / READ / UPDATE / DELETE (CRUD), allora possiamo progettare percorsi nella nostra applicazione Web che saranno in grado di dedurre quale azione di CRUD stiamo realizzando.

Ad esempio, in un'applicazione Ruby on Rails possiamo costruire la nostra app Web in modo tale che se un utente che ha effettuato l'accesso visita http://store.com/account/logout , il GET di quella pagina può essere visualizzato come l'utente che tenta di disconnettersi. Nel nostro controller di rotaie avremmo creato un'azione che disconnettesse l'utente e lo rimandasse alla home page.

Un GET sulla pagina di accesso genererebbe un modulo. un POST sulla pagina di accesso verrebbe visualizzato come un tentativo di accesso e prendere i dati POST e usarli per accedere.

Per me, è una pratica utilizzare metodi HTTP associati al significato del loro database e quindi costruire un sistema di autenticazione tenendo presente che non è necessario passare da un ID di sessione o tenere traccia delle sessioni.

Sto ancora imparando: se trovi qualcosa che ho detto di essere sbagliato, per favore correggimi e se impari di più pubblicalo di nuovo qui. Grazie.

L'uso di un'infrazione di chiave pubblica in cui la registrazione di una chiave implica un'adeguata associazione garantisce che la chiave pubblica sia vincolata all'individuo a cui è assegnata in modo da garantire il non ripudio

Vedi http://en.wikipedia.org/wiki/Public_key_infrastructure . Se si seguono gli standard PKI corretti, la persona o l'agente che utilizza impropriamente la chiave rubata può essere identificato e bloccato. Se l'agente deve utilizzare un certificato, l'associazione diventa piuttosto stretta. Un ladro intelligente e in rapido movimento può fuggire, ma lasciano più briciole.

Suggerimenti validi per proteggere qualsiasi applicazione web

Se vuoi proteggere la tua applicazione, allora dovresti assolutamente iniziare a usare HTTPS invece di HTTP , questo assicura un canale sicuro di creazione tra te & amp; gli utenti che impediranno di annusare i dati restituiti & amp; agli utenti & amp; contribuirà a mantenere riservati i dati scambiati.

È possibile utilizzare JWT (token Web JSON) per proteggere le API RESTful , questo ha molti vantaggi rispetto alle sessioni lato server, i vantaggi sono principalmente:

1- Più scalabile, poiché i tuoi server API non dovranno mantenere sessioni per ogni utente (che può essere un grosso fardello quando hai molte sessioni)

2- JWT sono autonomi & amp; avere le affermazioni che definiscono il ruolo dell'utente, ad esempio & amp; a cosa può accedere & amp; rilasciato alla data & amp; data di scadenza (dopo la quale JWT non sarà valido)

3- Più facile da gestire su bilanciamento del carico e amp; se disponi di più server API in quanto non dovrai condividere i dati della sessione né configurare il server per indirizzare la sessione allo stesso server, ogni volta che una richiesta con un JWT raggiunge qualsiasi server può essere autenticata & amp; autorizzato

4- Meno pressione sul tuo DB e non dovrai costantemente archiviare & amp; recuperare ID sessione & amp; dati per ogni richiesta

5- I JWT non possono essere manomessi se si utilizza una chiave avanzata per firmare il JWT, quindi ci si può fidare dei reclami nel JWT inviati con la richiesta senza dover controllare la sessione utente & amp; che sia autorizzato o meno, puoi semplicemente controllare JWT & amp; allora sei pronto per sapere chi & amp; cosa può fare questo utente.

Molte librerie offrono semplici modi per creare & amp; convalida JWT nella maggior parte dei linguaggi di programmazione, ad esempio: in node.js uno dei più popolari è jsonwebtoken

Poiché le API REST generalmente mirano a mantenere il server senza stato, quindi i JWT sono più compatibili con quel concetto poiché ogni richiesta viene inviata con token di autorizzazione autonomo (JWT) senza che il server debba tenere traccia della sessione dell'utente rispetto alle sessioni che rendono il server con stato in modo che ricordi l'utente & amp; il suo ruolo, tuttavia, le sessioni sono anche ampiamente utilizzate & amp; hanno i loro professionisti, che puoi cercare se vuoi.

Una cosa importante da notare è che devi consegnare in sicurezza il JWT al client usando HTTPS & amp; salvarlo in un luogo sicuro (ad esempio nella memoria locale).

Puoi saperne di più sui JWT da questo link

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top