wcf cosa - Best practice per la protezione di un'API / servizio web REST




sono example (16)

Il fatto che il mondo SOAP sia abbastanza ben coperto dagli standard di sicurezza non significa che sia sicuro per impostazione predefinita. In primo luogo, gli standard sono molto complessi. La complessità non è un ottimo amico di sicurezza e le vulnerabilità di implementazione come gli attacchi di wrapping di firma XML sono endemiche qui.

Per quanto riguarda l'ambiente .NET non mi sarà di grande aiuto, ma "Costruire servizi Web con Java" (un mattone con ~ 10 autori) mi ha aiutato molto a capire l'architettura di sicurezza WS- * e, soprattutto, le sue stranezze.

Quando si progetta un'API o un servizio REST esistono delle best practice consolidate per la gestione della sicurezza (autenticazione, autorizzazione, gestione dell'identità)?

Quando si crea un'API SOAP si ha WS-Security come guida e molta letteratura sull'argomento. Ho trovato meno informazioni sulla protezione degli endpoint REST.

Mentre capisco che REST intenzionalmente non ha specifiche analoghe a WS- * spero che siano emerse migliori pratiche o modelli raccomandati.

Qualsiasi discussione o link a documenti pertinenti sarebbe molto apprezzato. Se è importante, utilizzeremo WCF con i messaggi serializzati POX / JSON per le nostre API / servizi REST creati utilizzando la v3.5 di .NET Framework.


Come @Nathan finì con quale è una semplice intestazione HTTP, e alcuni avevano detto OAuth2 e certificati SSL lato client. L'essenza di ciò è questa ... la tua API REST non dovrebbe avere a che fare con la sicurezza in quanto dovrebbe essere al di fuori dell'ambito dell'API.

Al suo posto dovrebbe essere posto un livello di sicurezza, che si tratti di un'intestazione HTTP dietro un proxy Web (un approccio comune come SiteMinder, Zermatt o anche Apache HTTPd) o complicato come OAuth 2.

La cosa fondamentale è che le richieste dovrebbero funzionare senza alcuna interazione con l'utente finale. Tutto ciò che serve è garantire che la connessione all'API REST sia autenticata. In Java EE abbiamo la nozione di userPrincipal che può essere ottenuta su HttpServletRequest . Nel descrittore di deployment viene inoltre gestito che un pattern URL può essere protetto in modo che il codice API REST non debba più controllarlo.

Nel mondo WCF, vorrei utilizzare ServiceSecurityContext.Current per ottenere l'attuale contesto di sicurezza. È necessario configurare l'applicazione per richiedere l'autenticazione.

C'è un'eccezione all'affermazione che ho sopra e che è l'uso di un nonce per impedire i replay (che possono essere attacchi o qualcuno che invia gli stessi dati due volte). Quella parte può essere gestita solo nel livello dell'applicazione.


Uno dei migliori post che abbia mai visto per quanto riguarda la sicurezza in relazione a REST è finito a 1 RainDrop . Le API di MySpace usano OAuth anche per la sicurezza e hai pieno accesso ai loro canali personalizzati nel codice RestChess, con cui ho fatto molte esplorazioni. Questo è stato demoato su Mix e puoi trovare il post here .


Ho cercato molto sulla sicurezza di ws e abbiamo finito con l'utilizzo di token tramite cookie dal client al server per autenticare le richieste. Ho utilizzato la sicurezza di primavera per l'autorizzazione delle richieste in servizio perché dovevo autenticare e autorizzare ogni richiesta in base a criteri di sicurezza specificati che erano già presenti nel DB.


C'è una grande lista di controllo trovata su Github :

Autenticazione

  • Non reinventare la ruota in Autenticazione, generazione di token, memorizzazione della password. Usa gli standard.

  • Usa le funzioni Max Retry e jail in Login.

  • Usa la crittografia su tutti i dati sensibili.

JWT (Token Web JSON)

  • Usa una chiave complicata a caso (JWT Secret) per fare in modo che la forza bruta imponga il token molto duramente.

  • Non estrarre l'algoritmo dal payload. Forza l'algoritmo nel backend (HS256 o RS256).

  • Effettuare la scadenza del token ( TTL , RTTL ) il più breve possibile.

  • Non memorizzare dati sensibili nel payload JWT , può essere decodificato facilmente.

OAuth

  • Convalidare sempre redirect_uri lato server per consentire solo gli URL autorizzati.

  • Cerca sempre di scambiare codice e non token (non consentire response_type=token ).

  • Utilizza il parametro di stato con un hash casuale per impedire CSRF sul processo di autenticazione OAuth .

  • Definire l'ambito predefinito e convalidare i parametri di ambito per ciascuna applicazione.

Accesso

  • Limitare le richieste (Throttling) per evitare attacchi DDoS / brute-force.

  • Usa HTTPS sul lato server per evitare MITM (Man In The Middle Attack)

  • Utilizza l'intestazione HSTS con SSL per evitare attacchi SSL Strip.

Ingresso

  • Utilizzare il metodo HTTP appropriato in base all'operazione: GET (leggi), POST (crea), PUT/PATCH (sostituisci / aggiorna) e DELETE (per eliminare un record) e risponde con 405 Method Not Allowed se il metodo richiesto non è 'appropriato per la risorsa richiesta.

  • Convalidare il tipo di contenuto su richiesta Accept intestazione (Negoziazione del contenuto) per consentire solo il formato supportato (ad es. application/xml , application/json , ecc.) E rispondere con la risposta 406 Not Acceptable se non corrisponde.

  • Convalidare il content-type di content-type dei dati inviati come si accetta (ad esempio application/x-www-form-urlencoded , multipart/form-data , application/json , ecc.).

  • Convalidare l'input dell'utente per evitare le vulnerabilità comuni (es. XSS, SQL-Injection, Remote Code Execution, ecc.).

  • Non utilizzare dati sensibili (credenziali, password, token di sicurezza o chiavi API) nell'URL, ma utilizzare l'intestazione di Authorization standard.

  • Utilizzare un servizio gateway API per abilitare la memorizzazione nella cache, i criteri di Rate Limit (ad es. Quota, arresto limite, limite di velocità simultanea) e distribuire le risorse API in modo dinamico.

in lavorazione

  • Controllare se tutti gli endpoint sono protetti dietro l'autenticazione per evitare processi di autenticazione danneggiati.

  • L'ID risorsa personale dell'utente deve essere evitato. Usa / me / ordini invece di / utente / 654321 / ordini.

  • Non aumentare automaticamente gli ID. Utilizzare invece UUID.

  • Se stai analizzando i file XML, assicurati che l'analisi delle entità non sia abilitata per evitare XXE (attacco di entità esterna XML).

  • Se stai analizzando i file XML, assicurati che l'espansione dell'entità non sia abilitata per evitare la bomba Billion Laughs / XML tramite un attacco esponenziale di espansione dell'entità.

  • Utilizzare un CDN per i caricamenti di file.

  • Se hai a che fare con un'enorme quantità di dati, usa Workers e Queues per elaborare il più possibile in background e restituire la risposta velocemente per evitare il blocco HTTP.

  • Non dimenticare di disattivare la modalità DEBUG .

Produzione

  • Invia X-Content-Type-Options: nosniff header.

  • Invia X-Frame-Options: deny intestazione.

  • Invia Content-Security-Policy: default-src 'none' intestazione.

  • Rimuovi le intestazioni delle impronte digitali: X-Powered-By , Server , X-AspNet-Version ecc.

  • Forza il content-type per la risposta, se restituisci l' application/json il tipo di contenuto della tua risposta è application/json .

  • Non restituire dati sensibili come credenziali, password, token di sicurezza.

  • Restituire il codice di stato corretto in base all'operazione completata. (ad es. 200 OK , 400 Bad Request 401 Unauthorized , 401 Unauthorized , 405 Method Not Allowed , ecc.).



È passato un po 'di tempo ma la domanda è ancora pertinente, anche se la risposta potrebbe essere cambiata un po'.

Un gateway API sarebbe una soluzione flessibile e altamente configurabile. Ho provato e utilizzato KONG un bel po 'e mi è piaciuto molto quello che ho visto. KONG fornisce un'API REST di amministrazione propria che puoi utilizzare per gestire gli utenti.

Express-gateway.io è più recente ed è anche un gateway API.


Come detto, Amazon S3 è un buon modello con cui lavorare. Le loro firme di richiesta hanno alcune caratteristiche (come l'incorporazione di un timestamp) che aiutano a prevenire la riproduzione di richieste accidentali e dannose.

La cosa bella di HTTP Basic è che praticamente tutte le librerie HTTP lo supportano. Ovviamente, in questo caso, è necessario richiedere SSL perché inviare password in chiaro su Internet è quasi universalmente una cosa negativa. È preferibile eseguire il Digest di base quando si utilizza SSL perché, anche se il chiamante sa già che sono richieste le credenziali, Digest richiede un ulteriore roundtrip per scambiare il valore nonce. Con Basic, i chiamanti inviano semplicemente le credenziali la prima volta.

Una volta stabilita l'identità del cliente, l'autorizzazione è in realtà solo un problema di implementazione. Tuttavia, è possibile delegare l'autorizzazione ad altri componenti con un modello di autorizzazione esistente. Ancora una volta la cosa bella di Basic qui è che il tuo server finisce con una copia in chiaro della password del client che puoi semplicemente passare ad un altro componente all'interno della tua infrastruttura, se necessario.


Grazie per l'eccellente consiglio. Abbiamo finito con l'utilizzo di un'intestazione HTTP personalizzata per passare un token di identità dal client al servizio, in preparazione per l'integrazione della nostra API RESTful con l'imminente framework Zermatt Identity di Microsoft. Ho descritto il problema here e la nostra soluzione here . Ho anche preso il consiglio di tweakt e ho acquistato RESTful Web Services - un ottimo libro se stai costruendo una API RESTful di qualsiasi tipo.


REST in sé non offre standard di sicurezza, ma cose come OAuth e SAML stanno rapidamente diventando gli standard in questo spazio. Tuttavia, l'autenticazione e l'autorizzazione sono solo una piccola parte di ciò che devi considerare. Molte delle vulnerabilità note relative alle applicazioni Web si applicano molto alle API di REST. È necessario considerare la convalida dell'input, il cracking della sessione, i messaggi di errore inappropriati, le vulnerabilità interne dei dipendenti e così via. È un grande argomento.


OWASP (Open Web Application Security Project) ha alcuni trucchi che trattano tutti gli aspetti dello sviluppo di applicazioni Web. Questo progetto è una fonte di informazioni molto preziosa e affidabile. Per quanto riguarda i servizi REST è possibile controllare questo: https://www.owasp.org/index.php/REST_Security_Cheat_Sheet


Non ci sono standard per REST diversi da HTTP. Ci sono servizi REST stabiliti là fuori. Ti suggerisco di dare un'occhiata a loro e avere un'idea di come funzionano.

Ad esempio, abbiamo preso in prestito molte idee dal servizio S3 REST di Amazon durante lo sviluppo del nostro. Ma abbiamo scelto di non utilizzare il modello di sicurezza più avanzato basato sulle firme delle richieste. L'approccio più semplice è l'autenticazione HTTP Basic su SSL. Devi decidere cosa funziona meglio nella tua situazione.

Inoltre, consiglio vivamente il libro RESTful Web Services di O'reilly. Spiega i concetti fondamentali e fornisce alcune buone pratiche. In genere puoi prendere il modello che forniscono e associarlo alla tua applicazione.


Voglio aggiungere (in linea con stinkeymatt), la soluzione più semplice sarebbe quella di aggiungere certificati SSL al tuo sito. In altre parole, assicurati che il tuo URL sia HTTPS: //. Ciò coprirà la sicurezza del trasporto (bang for the buck). Con l'URL di RESTful, l'idea è di mantenerla semplice (a differenza di WS * security / SAML), è possibile utilizzare oAuth2 / openID connect o anche Basic Auth (in casi semplici). Ma avrai ancora bisogno di SSL / HTTPS. Si prega di verificare la sicurezza di API Web ASP 2 qui: http://www.asp.net/web-api/overview/security (Articoli e video)


Puoi anche dare un'occhiata a OAuth , un protocollo aperto emergente per l'autorizzazione basata su token che si rivolge in modo specifico alle http apis.

È molto simile all'approccio adottato da flickr e ricorda l' apis del latte "resto" (non necessariamente buoni esempi di apis riposati, ma buoni esempi dell'approccio basato sui token).


Tutti in queste risposte hanno trascurato il vero controllo / autorizzazione degli accessi.

Se ad esempio le tue API / servizi web REST riguardano il POSTing / GETing delle cartelle cliniche, potresti voler definire la polizza di controllo degli accessi su chi può accedere ai dati e in quali circostanze. Per esempio:

  • i medici possono ottenere la cartella clinica di un paziente con cui hanno una relazione di assistenza
  • nessuno può inviare dati medici al di fuori delle ore di pratica (ad esempio da 9 a 5)
  • gli utenti finali possono ottenere le cartelle cliniche di loro proprietà o le cartelle cliniche dei pazienti per i quali sono tutori
  • gli infermieri possono AGGIORNARE la cartella clinica di un paziente che appartiene alla stessa unità dell'infermiere.

Al fine di definire e implementare tali autorizzazioni a grana fine, sarà necessario utilizzare un linguaggio di controllo degli accessi basato su attributi chiamato XACML, il linguaggio di markup del controllo di accesso eXtensible.

Gli altri standard qui sono i seguenti:

  • OAuth: id. federazione e delega di autorizzazione, ad esempio lasciando che un servizio agisca per mio conto su un altro servizio (Facebook può postare sul mio Twitter)
  • SAML: identity federation / web SSO. SAML parla molto di chi è l'utente.
  • Standard WS-Security / WS- *: si concentrano sulla comunicazione tra i servizi SOAP. Sono specifici del formato di messaggistica a livello di applicazione (SOAP) e trattano aspetti di messaggistica, ad es. Affidabilità, sicurezza, riservatezza, integrità, atomicità, eventi ... Nessuno copre il controllo degli accessi e tutti sono specifici per SOAP.

XACML è indipendente dalla tecnologia. Può essere applicato a applicazioni Java, .NET, Python, Ruby ... servizi Web, API REST e altro ancora.

Le seguenti sono risorse interessanti:


L'URL NON deve contenere le versioni. La versione non ha nulla a che fare con "idea" della risorsa che stai richiedendo. Dovresti cercare di pensare all'URL come a un percorso per il concetto che desideri - non a come vuoi che l'oggetto venga restituito. La versione detta la rappresentazione dell'oggetto, non il concetto dell'oggetto. Come hanno detto altri poster, dovresti specificare il formato (inclusa la versione) nell'intestazione della richiesta.

Se si guarda la richiesta HTTP completa per gli URL che hanno versioni, appare come questa:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

L'intestazione contiene la riga che contiene la rappresentazione richiesta ("Accept: application / xml"). Ecco dove dovrebbe andare la versione. Tutti sembrano sorvolare sul fatto che si potrebbe desiderare la stessa cosa in diversi formati e che il client dovrebbe poter chiedere quello che vuole. Nell'esempio precedente, il client richiede QUALSIASI rappresentazione XML della risorsa, non la vera rappresentazione di ciò che vuole. Il server potrebbe, in teoria, restituire qualcosa completamente estraneo alla richiesta fintanto che era XML e dovrebbe essere analizzato per rendersi conto che è sbagliato.

Un modo migliore è:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Inoltre, diciamo che i clienti pensano che l'XML sia troppo prolisso e ora vogliono invece JSON. Negli altri esempi dovresti avere un nuovo URL per lo stesso cliente, quindi ti ritroveremmo con:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(o qualcosa di simile). Quando infatti ogni richiesta HTTP contiene il formato che stai cercando:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

Usando questo metodo, hai molta più libertà nel design e aderisci effettivamente all'idea originale di REST. È possibile modificare le versioni senza interrompere i client o modificare i client in modo incrementale con la modifica delle API. Se si sceglie di interrompere il supporto di una rappresentazione, è possibile rispondere alle richieste con codice di stato HTTP o codici personalizzati. Il client può anche verificare che la risposta sia nel formato corretto e convalidare l'XML.

Ci sono molti altri vantaggi e ne discuto alcuni qui sul mio blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Un ultimo esempio per mostrare come mettere la versione nell'URL è brutto. Diciamo che volete qualche informazione all'interno dell'oggetto, e avete messo in versione i vostri vari oggetti (i clienti sono v3.0, gli ordini sono v2.0 e shipto object è v4.2). Ecco il brutto URL che devi fornire nel client:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/






wcf security rest authorization rest-security