REST API Token Tabanlı Kimlik Doğrulama


122

Kimlik doğrulama gerektiren bir REST API geliştiriyorum. Kimlik doğrulamanın kendisi HTTP üzerinden harici bir web hizmeti aracılığıyla gerçekleştiğinden, kimlik doğrulama hizmetini tekrar tekrar çağırmaktan kaçınmak için belirteçleri dağıtacağımızı düşündüm. Bu da beni düzgün bir şekilde ilk soruma getiriyor:

Bu, istemcilerin her istekte HTTP Temel Kimlik Doğrulamasını kullanmasını gerektirmekten ve kimlik doğrulama hizmeti sunucu tarafındaki çağrıları önbelleğe almaktan gerçekten daha mı iyi?

Temel Kimlik Doğrulama çözümü, içerik taleplerinin başlayabilmesi için sunucuya tam bir gidiş dönüş gerektirmeme avantajına sahiptir. Belirteçler kapsam açısından potansiyel olarak daha esnek olabilir (yani yalnızca belirli kaynaklara veya eylemlere haklar verir), ancak bu, daha basit kullanım durumumdan OAuth bağlamına daha uygun görünmektedir.

Şu anda jetonlar şu şekilde edinilir:

curl -X POST localhost/token --data "api_key=81169d80...
                                     &verifier=2f5ae51a...
                                     &timestamp=1234567
                                     &user=foo
                                     &pass=bar"

api_key, timestampVe verifiertüm isteklere göre gereklidir. "Doğrulayıcı" şu şekilde döndürülür:

sha1(timestamp + api_key + shared_secret)

Niyetim, yalnızca bilinen taraflardan gelen aramalara izin vermek ve aramaların aynen tekrar kullanılmasını önlemektir.

Bu yeterince iyi mi? Underkill? Aşırı yükleme?

Müşteriler ellerinde bir jetonla kaynakları edinebilir:

curl localhost/posts?api_key=81169d80...
                    &verifier=81169d80...
                    &token=9fUyas64...
                    &timestamp=1234567

Mümkün olan en basit çağrı için, bu korkunç derecede ayrıntılı görünüyor. shared_secretÇıkarılabileceğini varsaydığım bir iOS uygulamasına (en azından) gömülmeyi düşünürsek , bu yanlış bir güvenlik duygusunun ötesinde bir şey sunuyor mu?


2
Sha1 (timestamp + api_key + shard_secret) kullanmak yerine, daha iyi bir güvenlik hashingi için hmac (shared_secret, timpestamp + api_key) kullanmalısınız en.wikipedia.org/wiki/Hash-based_message_authentication_code
Miguel A. Carrasco

@ MiguelA.Carrasco Ve 2017'de bCrypt'in yeni hashing aracı olduğu konusunda fikir birliği var gibi görünüyor.
Shawn

Yanıtlar:


94

Her şeyi ayırmama ve her soruna ayrı ayrı yaklaşmayı çözmeme izin verin:

Kimlik Doğrulama

Kimlik doğrulama için, baseauth protokol düzeyinde olgun bir çözüm olma avantajına sahiptir. Bu çok şey ifade ediyor "daha sonra ortaya çıkabilir" sorununun sizin için zaten çözüldüğü . Örneğin, BaseAuth ile, kullanıcı aracıları parolanın bir parola olduğunu bilir, böylece parolayı önbelleğe alamazlar.

Kimlik doğrulama sunucusu yükü

Sunucunuzda kimlik doğrulamasını önbelleğe almak yerine kullanıcıya bir belirteç dağıtırsanız, yine de aynı şeyi yaparsınız: Kimlik doğrulama bilgilerini önbelleğe alma. Tek fark, önbelleğe alma sorumluluğunu kullanıcıya devretmenizdir. Bu, kullanıcı için kazançsız gereksiz emek gibi görünüyor, bu yüzden önerdiğiniz gibi bunu sunucunuzda şeffaf bir şekilde halletmenizi tavsiye ederim.

İletim Güvenliği

Bir SSL bağlantısı kullanabiliyorsanız, hepsi bu kadar, bağlantı güvenlidir *. Yanlışlıkla çoklu yürütmeyi önlemek için, birden çok url'yi filtreleyebilir veya kullanıcılardan URL'ye rastgele bir bileşen ("nonce") eklemelerini isteyebilirsiniz.

url = username:key@myhost.com/api/call/nonce

Bu mümkün değilse ve iletilen bilgiler gizli değilse, belirteç yaklaşımında önerdiğiniz gibi isteği bir hash ile güvence altına almanızı öneririm. Karma güvenlik sağladığından, kullanıcılarınızdan karmayı temel kimlik şifresi olarak sağlamaları için talimat verebilirsiniz. İyileştirilmiş sağlamlık için, tekrar saldırılarını önlemek için zaman damgası yerine rastgele bir dizeyi "tek sefer" olarak kullanmanızı öneririm (aynı saniye içinde iki yasal istek yapılabilir). Ayrı "paylaşılan gizli" ve "api anahtarı" alanları sağlamak yerine, api anahtarını paylaşılan sır olarak kullanabilir ve ardından gökkuşağı tablo saldırılarını önlemek için değişmeyen bir tuz kullanabilirsiniz. Kullanıcı adı alanı, kimlik doğrulamanın bir parçası olduğu için nonce'yi de koymak için iyi bir yer gibi görünüyor. Öyleyse şimdi şöyle temiz bir aramanız var:

nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:one_time_key@myhost.com/api/call

Bunun biraz zahmetli olduğu doğru. Bunun nedeni, protokol düzeyinde bir çözüm (SSL gibi) kullanmamanızdır. Bu nedenle, kullanıcılara bir tür SDK sağlamak iyi bir fikir olabilir, böylece en azından kendi başlarına geçmek zorunda kalmazlar. Bu şekilde yapmanız gerekirse, güvenlik seviyesini uygun buluyorum (sadece sağ-öldür).

Güvenli gizli depolama

Kimi engellemeye çalıştığına bağlı. Kullanıcının telefonuna erişimi olan kişilerin, kullanıcının adına REST hizmetinizi kullanmasını engelliyorsanız, hedef işletim sisteminde bir tür anahtarlık API'si bulmak ve SDK'nın (veya uygulayıcının) bunları depolamasını sağlamak iyi bir fikir olacaktır. orada anahtar. Bu mümkün değilse, en azından şifreleyerek ve şifrelenmiş verileri ve şifreleme anahtarını ayrı yerlerde depolayarak sırrı elde etmeyi biraz daha zorlaştırabilirsiniz.

Diğer yazılım satıcılarının, alternatif istemcilerin geliştirilmesini önlemek için API anahtarınızı almasını engellemeye çalışıyorsanız, yalnızca ayrı ayrı şifrele ve sakla yaklaşımı neredeyse işe yarar. Bu, beyaz kutu kripto ve bugüne kadar hiç kimse bu sınıftaki sorunlara gerçekten güvenli bir çözüm bulamadı. En azından yapabileceğiniz şey, kötüye kullanılan anahtarları yasaklayabilmeniz için her kullanıcı için hala tek bir anahtar vermektir.

(*) DÜZENLEME: SSL bağlantıları artık güvenli kabul edilmelidir olmadan doğrulamak için ek adımlar atıyor onları.


Teşekkürler cmc, tüm iyi noktalar ve düşünce için harika yemekler. S3 REST API kimlik doğrulama mekanizması gibi, yukarıda bahsettiğinize benzer bir belirteç / HMAC yaklaşımı benimsedik .
cantlin

Belirteci sunucuda önbelleğe alırsanız, aslında eski güzel oturum kimliğiyle aynı değil mi? Oturum kimliği kısa ömürlüdür ve ayrıca her istekte DB'nize isabetten kaçınmak için hızlı önbellek depolamasına da eklenir (uygularsanız). Gerçek RESTful & stateless tasarımda oturumlar olmamalıdır, ancak kimlik olarak bir belirteç kullanıyorsanız ve sonra yine de DB'ye basarsanız, bunun yerine oturum kimliğini kullanmanız daha iyi olmaz mı? Alternatif olarak, gerçek durum bilgisi olmayan tasarım için tüm oturum verileri için şifrelenmiş veya imzalanmış bilgiler içeren JSON web belirteçlerine gidebilirsiniz.
JustAMartin

16

Saf bir RESTful API, temel protokol standart özelliklerini kullanmalıdır:

  1. HTTP için RESTful API, mevcut HTTP standart başlıklarıyla uyumlu olmalıdır. Yeni bir HTTP üstbilgisi eklemek, REST ilkelerini ihlal eder. Tekerleği yeniden icat etmeyin, HTTP / 1.1 standartlarındaki tüm standart özellikleri kullanın - durum yanıt kodları, başlıklar vb. Dahil. RESTFul web hizmetleri, HTTP standartlarından yararlanmalı ve bunlara güvenmelidir.

  2. RESTful hizmetler VATANSIZ OLMALIDIR. Sunucudaki önceki REST isteklerinin durumunu hatırlamaya çalışan belirteç tabanlı kimlik doğrulama gibi tüm hileler REST ilkelerini ihlal eder. Yine, bu bir zorunluluktur; diğer bir deyişle, web sunucunuz, sunucuda herhangi bir oturum açma girişiminde bulunarak istek / yanıt bağlamıyla ilgili bilgileri sunucuya kaydederse, web hizmetiniz Durumsuz DEĞİLDİR. Ve eğer vatansız DEĞİLSE DİNLENMEZ.

Alt satır: Kimlik doğrulama / yetkilendirme amaçları için, HTTP standart yetkilendirme başlığını kullanmalısınız. Yani, kimlik doğrulaması yapılması gereken sonraki her isteğe HTTP yetkilendirme / kimlik doğrulama başlığını eklemelisiniz. REST API, HTTP Kimlik Doğrulama Şeması standartlarını takip etmelidir Bu başlığın nasıl biçimlendirilmesi gerektiğine ilişkin özellikler, RFC 2616 HTTP 1.1 standartlarında - bölüm 14.8 RFC 2616'nın Yetkilendirilmesi ve RFC 2617 HTTP Kimlik Doğrulaması: Temel ve Özet Erişim Kimlik Doğrulaması'nda tanımlanmıştır. .

Cisco Prime Performance Manager uygulaması için bir RESTful hizmeti geliştirdim. Ben RESTful API uyumluluğu hakkında daha fazla ayrıntı için söz konusu uygulama için yazdığı REST API belgesi için Google'da arama burada . Bu uygulamada, HTTP "Temel" Yetkilendirme şemasını kullanmayı seçtim. - bu REST API belgesinin 1.5 veya sonraki sürümlerine bakın ve belgede yetkilendirme arayın.


8
"Yeni bir HTTP üstbilgisi eklemek REST ilkelerini ihlal eder" Nasıl olur? Ve eğer bunu yapıyorsanız, belirli bir süre sonra sona eren bir parola ile belirli bir süre sonra sona eren bir simge arasındaki farkın (ilkelerle ilgili olarak) tam olarak ne olduğunu açıklamak çok nazik olabilirsiniz.
a better oliver

6
Kullanıcı adı + parola, her istekte bir istemci ile sunucu arasında değiştirilen bir belirteçtir (!). Bu jeton sunucuda tutulur ve bir yaşam süresi vardır. Parolanın süresi dolarsa, yeni bir parola almam gerekir. "Belirteç" i "sunucu oturumu" ile ilişkilendiriyorsunuz, ancak bu geçersiz bir sonuç. Hatta alakasız çünkü bir uygulama detayı olacaktır. Kullanıcı adı / parola dışındaki belirteçleri durum bilgisi olarak sınıflandırmanız tamamen yapaydır, imho.
daha iyi bir oliver

1
Bence orijinal sorunun bir parçası olan Temel Kimlik Doğrulama yerine RESTful ile neden bir uygulama yapılacağını motive etmelisiniz. Belki kodun dahil olduğu bazı iyi örneklere de bağlantı kurabilirsiniz. Bu konuda yeni başlayan biri olarak, teori pek çok iyi kaynakla yeterince açık görünmektedir, ancak uygulama yöntemi değildir ve örnekler kıvrımlıdır. Binlerce kez yapılmış bir şeyi zamanında uygulamak için özel kodlamayı gerektiriyor gibi görünmesini sinir bozucu buluyorum.
JPK

13
-1 "Sunucudaki önceki REST isteklerinin durumunu hatırlamaya çalışan belirteç tabanlı kimlik doğrulama gibi tüm hileler REST ilkelerini ihlal ediyor." belirteç tabanlı kimlik doğrulamanın önceki REST isteklerinin durumuyla hiçbir ilgisi yoktur ve REST'in durumsuzluğunu ihlal etmez .
Kerem Baydoğan

1
Öyleyse, buna göre, JSON Web Tokenları, kullanıcının durumunu (taleplerini) saklayabildikleri için REST ihlalidir? Her neyse, REST'i ihlal etmeyi ve bir "belirteç" olarak eski güzel oturum kimliğini kullanmayı tercih ederim, ancak ilk kimlik doğrulama, paylaşılan gizli ve çok kısa süreli zaman damgası kullanılarak imzalanmış veya şifrelenmiş kullanıcı adı + geçiş ile gerçekleştirilir (bu nedenle, herhangi biri yeniden oynatmaya çalışırsa başarısız olur ) o. "Kurumsal" bir uygulamada, oturum avantajlarını bir kenara atmak zordur (hemen hemen her istekte ihtiyaç duyulan bazı veriler için veritabanına ulaşmaktan kaçınmak), bu nedenle bazen gerçek vatansızlığı feda etmemiz gerekir.
JustAMartin

2

Web'de durum bilgisi olan bir protokol, her talepte bir tarayıcı ve bir sunucu arasında (çerez başlığı veya URI yeniden yazma yoluyla) değiştirilen geçici bir simgeye sahip olmaya dayanır. Bu simge genellikle sunucu tarafında oluşturulur ve opak bir parçadır. belirli bir yaşam süresine sahip veri ve tek amacı belirli bir web kullanıcı aracısını tanımlamaktır. Yani, belirteç geçicidir ve web sunucusunun bu konuşma süresince bir istemci kullanıcı aracısı adına sürdürmesi gereken bir DURUM olur. Bu nedenle, bu şekilde bir belirteç kullanan iletişim DURUMLUDUR. Ve istemci ile sunucu arasındaki konuşma DURUMLU ise, RESTful değildir.

Kullanıcı adı / parola (Yetkilendirme başlığında gönderilir) genellikle bir kullanıcıyı tanımlamak amacıyla veritabanında saklanır. Bazen kullanıcı başka bir uygulamayı kastetebilir; ancak kullanıcı adı / şifre ASLA belirli bir web istemcisi kullanıcı aracısını tanımlamayı amaçlamaz. Yetkilendirme başlığındaki (HTTP Temel Yetkilendirmeyi takiben) kullanıcı adı / şifre kullanımına dayalı olarak bir web aracısı ile sunucu arasındaki konuşma DURUMSUZdur çünkü web sunucusu ön ucu herhangi bir STATE bilgisi oluşturmuyor veya tutmuyorbelirli bir web istemcisi kullanıcı aracısı adına ne olursa olsun. Ve REST anlayışıma göre, protokol, istemciler ve sunucu arasındaki konuşmanın DURUMSUZ olması gerektiğini açıkça belirtiyor. Bu nedenle, gerçek bir RESTful hizmetine sahip olmak istiyorsak, her bir çağrı için Yetkilendirme başlığında kullanıcı adı / şifre (önceki yazımda bahsedilen RFC'ye bakın) kullanmalıyız, duyumsal bir simge türü DEĞİL (örn. Web sunucularında oluşturulan oturum belirteçleri) , Yetkilendirme sunucularında oluşturulan OAuth jetonları vb.).

Aranan birkaç REST sağlayıcısının, HTTP üstbilgilerinde "Yetkilendirme: Taşıyıcı" olarak iletilmek üzere OAuth1 veya OAuth2 kabul jetonları gibi jetonlar kullandığını anlıyorum. Ancak, bana öyle geliyor ki, bu belirteçleri RESTful hizmetleri için kullanmak, REST'in benimsediği anlamına gelen gerçek STATELESS'i ihlal eder; çünkü bu belirteçler, belirli bir web istemcisi kullanıcı aracısını belirli bir web istemcisi / sunucu görüşmesinin geçerli süresi boyunca tanımlamak için sunucu tarafında oluşturulan / tutulan geçici veri parçalarıdır. Bu nedenle, bu OAuth1 / 2 belirteçlerini kullanan herhangi bir hizmet, STATELESS protokolünün TRUE anlamına bağlı kalmak istiyorsak REST olarak adlandırılmamalıdır.

Rubens

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.