c# - एएसपी.नेट वेब एपीआई कैसे सुरक्षित करें




asp.net-mvc oauth asp.net-web-api (6)

मैं एएसपी.नेट वेब एपीआई का उपयोग कर एक रीस्टफुल वेब सेवा बनाना चाहता हूं कि तीसरे पक्ष के डेवलपर मेरे एप्लिकेशन के डेटा तक पहुंचने के लिए उपयोग करेंगे।

मैंने ओएथ के बारे में बहुत कुछ पढ़ा है और यह मानक प्रतीत होता है, लेकिन यह दस्तावेज के साथ एक अच्छा नमूना ढूंढ रहा है कि यह कैसे काम करता है (और वास्तव में यह काम करता है!) अविश्वसनीय रूप से कठिन लगता है (विशेष रूप से ओएथ के लिए नौसिखिया के लिए)।

क्या कोई ऐसा नमूना है जो वास्तव में बनाता है और काम करता है और दिखाता है कि इसे कैसे कार्यान्वित किया जाए?

मैंने कई नमूने डाउनलोड किए हैं:

  • DotNetOAuth - दस्तावेज़ीकरण एक नौसिखिया परिप्रेक्ष्य से निराशाजनक है
  • Thinktecture - इसे बनाने के लिए नहीं मिल सकता है

मैंने ब्लॉगों को एक साधारण टोकन-आधारित योजना ( this तरह) का सुझाव दिया है - ऐसा लगता है कि यह पहिया का पुन: आविष्कार करने जैसा लगता है लेकिन इसका अवधारणा काफी सरल होने का लाभ है।

ऐसा लगता है कि इस तरह के कई सवाल SO पर हैं लेकिन कोई अच्छा जवाब नहीं है।

इस जगह में सब लोग क्या कर रहे हैं?


Answers

@ कुओंग ले के उत्तर में निरंतरता में, रीप्ले हमले को रोकने के लिए मेरा दृष्टिकोण होगा

// साझा निजी कुंजी (या उपयोगकर्ता का पासवर्ड) का उपयोग कर क्लाइंट पक्ष पर यूनिक्स समय एन्क्रिप्ट करें

// सर्वर पर अनुरोध हेडर के हिस्से के रूप में इसे भेजें (वेब ​​एपीआई)

// साझा निजी कुंजी (या उपयोगकर्ता का पासवर्ड) का उपयोग कर सर्वर पर यूनिक्स टाइम (WEB API) को डिक्रिप्ट करें

// क्लाइंट के यूनिक्स समय और सर्वर के यूनिक्स समय के बीच समय अंतर की जांच करें, x सेकंड से अधिक नहीं होना चाहिए

// यदि उपयोगकर्ता आईडी / हैश पासवर्ड सही हैं और डिक्रिप्ट किया गया यूनिक्सटाइम सर्वर समय के x सेकंड के भीतर है तो यह एक वैध अनुरोध है


अद्यतन करें:

मैंने अपना दूसरा जवाब दिया है कि जेडब्ल्यूटी में रुचि रखने वाले किसी भी व्यक्ति के लिए यहां वेब एपीआई के लिए जेडब्ल्यूटी प्रमाणीकरण का उपयोग कैसे करें:

Asp.Net वेब एपीआई के लिए जेडब्ल्यूटी प्रमाणीकरण

हमने वेब एपीआई सुरक्षित करने के लिए एचएमएसी प्रमाणीकरण लागू करने में कामयाब रहे हैं, और यह ठीक काम करता है। एचएमएसी प्रमाणीकरण प्रत्येक उपभोक्ता के लिए एक गुप्त कुंजी का उपयोग करता है, जो उपभोक्ता और सर्वर दोनों को एचएमएसी संदेश भेजना है, एचएमएसी 256 का उपयोग किया जाना चाहिए। ज्यादातर मामलों में, उपभोक्ता का पासवर्ड धोखा दिया जाता है एक गुप्त कुंजी के रूप में प्रयोग किया जाता है।

संदेश सामान्य रूप से HTTP अनुरोध में डेटा से बनाया गया है, या यहां तक ​​कि अनुकूलित डेटा जो HTTP शीर्षलेख में जोड़ा गया है, संदेश में निम्न शामिल हो सकते हैं:

  1. टाइमस्टैंप: अनुरोध जो अनुरोध भेजा जाता है (यूटीसी या जीएमटी)
  2. HTTP क्रिया: प्राप्त करें, पोस्ट करें, पुट करें, हटाएं।
  3. डेटा और क्वेरी स्ट्रिंग पोस्ट करें,
  4. यूआरएल

हुड के तहत, एचएमएसी प्रमाणीकरण होगा:

उपभोक्ता हस्ताक्षर (एचएमएसी हैश का आउटपुट) बनाने के बाद वेब सर्वर पर HTTP अनुरोध भेजता है, HTTP अनुरोध का टेम्पलेट:

User-Agent: {agent}   
Host: {host}   
Timestamp: {timestamp}
Authentication: {username}:{signature}

अनुरोध प्राप्त करने के लिए उदाहरण:

GET /webapi.hmac/api/values

User-Agent: Fiddler    
Host: localhost    
Timestamp: Thursday, August 02, 2012 3:30:32 PM 
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=

हस्ताक्षर प्राप्त करने के लिए हैश को संदेश:

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n

क्वेरी स्ट्रिंग के साथ POST अनुरोध के लिए उदाहरण (नीचे हस्ताक्षर सही नहीं है, बस एक उदाहरण है)

POST /webapi.hmac/api/values?key2=value2

User-Agent: Fiddler    
Host: localhost    
Content-Type: application/x-www-form-urlencoded
Timestamp: Thursday, August 02, 2012 3:30:32 PM 
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=

key1=value1&key3=value3

हस्ताक्षर प्राप्त करने के लिए हैश को संदेश

GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3

कृपया ध्यान दें कि फॉर्म डेटा और क्वेरी स्ट्रिंग क्रम में होनी चाहिए, इसलिए सर्वर पर कोड क्वेरी स्ट्रिंग प्राप्त करें और सही संदेश बनाने के लिए डेटा बनाएं।

जब HTTP अनुरोध सर्वर पर आता है, तो जानकारी प्राप्त करने के अनुरोध को पार्स करने के लिए प्रमाणीकरण एक्शन फ़िल्टर लागू किया जाता है: HTTP क्रिया, टाइमस्टैम्प, यूरी, फॉर्म डेटा और क्वेरी स्ट्रिंग, फिर इनके आधार पर हस्ताक्षर (एचएमएसी हैश का उपयोग) गुप्त के साथ सर्वर पर कुंजी (हैश पासवर्ड)।

अनुरोध पर उपयोगकर्ता नाम के साथ डेटाबेस से गुप्त कुंजी मिल गई है।

फिर सर्वर कोड अनुरोध पर हस्ताक्षर की तुलना हस्ताक्षर के साथ करता है; यदि बराबर है, प्रमाणीकरण पारित किया जाता है, अन्यथा, यह असफल रहा।

हस्ताक्षर बनाने के लिए कोड:

private static string ComputeHash(string hashedPassword, string message)
{
    var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
    string hashString;

    using (var hmac = new HMACSHA256(key))
    {
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
        hashString = Convert.ToBase64String(hash);
    }

    return hashString;
}

तो, रीप्ले हमले को कैसे रोकें?

टाइमस्टैम्प के लिए बाधा जोड़ें, कुछ ऐसा:

servertime - X minutes|seconds  <= timestamp <= servertime + X minutes|seconds 

(servertime: अनुरोध करने का समय सर्वर पर आ रहा है)

और, स्मृति में अनुरोध के हस्ताक्षर को कैश करें (मेमोरी कैश का उपयोग करें, समय की सीमा में रखना चाहिए)। यदि अगला अनुरोध पिछले अनुरोध के साथ एक ही हस्ताक्षर के साथ आता है, तो इसे अस्वीकार कर दिया जाएगा।

डेमो कोड यहां के रूप में रखा गया है: https://github.com/cuongle/Hmac.WebApi


क्या आपने DevDefined.OAuth की कोशिश की है?

मैंने इसे अपने वेबएपी को 2-लेगेड ओथ के साथ सुरक्षित करने के लिए उपयोग किया है। मैंने PHP क्लाइंट के साथ सफलतापूर्वक इसका परीक्षण किया है।

इस पुस्तकालय का उपयोग करके OAuth के लिए समर्थन जोड़ने में काफी आसान है। यहां बताया गया है कि आप एएसपी.नेट एमवीसी वेब एपीआई के लिए प्रदाता को कैसे कार्यान्वित कर सकते हैं:

1) DevDefined.OAuth का स्रोत कोड प्राप्त करें: https://github.com/bittercoder/DevDefined.OAuth - नवीनतम संस्करण OAuthContextBuilder एक्स्टेंसिबिलिटी के लिए अनुमति देता है।

2) लाइब्रेरी बनाएं और इसे अपने वेब एपीआई प्रोजेक्ट में संदर्भित करें।

3) HttpRequestMessage से संदर्भ बनाने में सहायता के लिए एक कस्टम संदर्भ निर्माता बनाएं:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http;
using System.Web;

using DevDefined.OAuth.Framework;

public class WebApiOAuthContextBuilder : OAuthContextBuilder
{
    public WebApiOAuthContextBuilder()
        : base(UriAdjuster)
    {
    }

    public IOAuthContext FromHttpRequest(HttpRequestMessage request)
    {
        var context = new OAuthContext
            {
                RawUri = this.CleanUri(request.RequestUri), 
                Cookies = this.CollectCookies(request), 
                Headers = ExtractHeaders(request), 
                RequestMethod = request.Method.ToString(), 
                QueryParameters = request.GetQueryNameValuePairs()
                    .ToNameValueCollection(), 
            };

        if (request.Content != null)
        {
            var contentResult = request.Content.ReadAsByteArrayAsync();
            context.RawContent = contentResult.Result;

            try
            {
                // the following line can result in a NullReferenceException
                var contentType = 
                    request.Content.Headers.ContentType.MediaType;
                context.RawContentType = contentType;

                if (contentType.ToLower()
                    .Contains("application/x-www-form-urlencoded"))
                {
                    var stringContentResult = request.Content
                        .ReadAsStringAsync();
                    context.FormEncodedParameters = 
                        HttpUtility.ParseQueryString(stringContentResult.Result);
                }
            }
            catch (NullReferenceException)
            {
            }
        }

        this.ParseAuthorizationHeader(context.Headers, context);

        return context;
    }

    protected static NameValueCollection ExtractHeaders(
        HttpRequestMessage request)
    {
        var result = new NameValueCollection();

        foreach (var header in request.Headers)
        {
            var values = header.Value.ToArray();
            var value = string.Empty;

            if (values.Length > 0)
            {
                value = values[0];
            }

            result.Add(header.Key, value);
        }

        return result;
    }

    protected NameValueCollection CollectCookies(
        HttpRequestMessage request)
    {
        IEnumerable<string> values;

        if (!request.Headers.TryGetValues("Set-Cookie", out values))
        {
            return new NameValueCollection();
        }

        var header = values.FirstOrDefault();

        return this.CollectCookiesFromHeaderString(header);
    }

    /// <summary>
    /// Adjust the URI to match the RFC specification (no query string!!).
    /// </summary>
    /// <param name="uri">
    /// The original URI. 
    /// </param>
    /// <returns>
    /// The adjusted URI. 
    /// </returns>
    private static Uri UriAdjuster(Uri uri)
    {
        return
            new Uri(
                string.Format(
                    "{0}://{1}{2}{3}", 
                    uri.Scheme, 
                    uri.Host, 
                    uri.IsDefaultPort ?
                        string.Empty :
                        string.Format(":{0}", uri.Port), 
                    uri.AbsolutePath));
    }
}

4) ओएथ प्रदाता बनाने के लिए इस ट्यूटोरियल का प्रयोग करें: http://code.google.com/p/devdefined-tools/wiki/OAuthProvider । अंतिम चरण में (संरक्षित संसाधन उदाहरण तक पहुंच) आप इस कोड का उपयोग अपने AuthorizationFilterAttribute विशेषता में कर सकते हैं:

public override void OnAuthorization(HttpActionContext actionContext)
{
    // the only change I made is use the custom context builder from step 3:
    OAuthContext context = 
        new WebApiOAuthContextBuilder().FromHttpRequest(actionContext.Request);

    try
    {
        provider.AccessProtectedResourceRequest(context);

        // do nothing here
    }
    catch (OAuthException authEx)
    {
        // the OAuthException's Report property is of the type "OAuthProblemReport", it's ToString()
        // implementation is overloaded to return a problem report string as per
        // the error reporting OAuth extension: http://wiki.oauth.net/ProblemReporting
        actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
            {
               RequestMessage = request, ReasonPhrase = authEx.Report.ToString()
            };
    }
}

मैंने अपना खुद का प्रदाता लागू किया है इसलिए मैंने उपरोक्त कोड का परीक्षण नहीं किया है (बेशक WebApiOAuthContextBuilder जिसे मैं अपने प्रदाता में उपयोग कर रहा हूं) लेकिन इसे ठीक काम करना चाहिए।


मैं पहले सबसे सरल समाधानों से शुरू करने का सुझाव दूंगा - शायद आपके परिदृश्य में सरल HTTP मूल प्रमाणीकरण + HTTPS पर्याप्त है।

यदि नहीं (उदाहरण के लिए आप https का उपयोग नहीं कर सकते हैं, या अधिक जटिल कुंजी प्रबंधन की आवश्यकता है), तो आप दूसरों द्वारा सुझाए गए एचएमएसी-आधारित समाधानों पर एक नज़र डाल सकते हैं। इस तरह के एपीआई का एक अच्छा उदाहरण अमेज़ॅन एस 3 होगा ( http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html )

मैंने एएसपी.नेट वेब एपीआई में एचएमएसी आधारित प्रमाणीकरण के बारे में एक ब्लॉग पोस्ट लिखा था। यह वेब एपीआई सेवा और वेब एपीआई क्लाइंट दोनों पर चर्चा करता है और कोड बिटबकेट पर उपलब्ध है। http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

वेब एपीआई में बेसिक प्रमाणीकरण के बारे में एक पोस्ट यहां दी गई है: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

याद रखें कि यदि आप तृतीय पक्षों को एपीआई प्रदान करने जा रहे हैं, तो आप क्लाइंट पुस्तकालयों को वितरित करने के लिए ज़िम्मेदार भी होंगे। मूल प्रमाणीकरण का यहां एक महत्वपूर्ण लाभ है क्योंकि यह बॉक्स के बाहर अधिकांश प्रोग्रामिंग प्लेटफ़ॉर्म पर समर्थित है। दूसरी तरफ, एचएमएसी मानक नहीं है और इसे कस्टम कार्यान्वयन की आवश्यकता होगी। ये अपेक्षाकृत सीधा होना चाहिए लेकिन अभी भी काम की आवश्यकता है।

पुनश्च। HTTPS + प्रमाणपत्रों का उपयोग करने का विकल्प भी है। http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/


वेब एपीआई ने सुरक्षा प्रदान करने के लिए एक विशेषता [Authorize] पेश की। इसे वैश्विक रूप से सेट किया जा सकता है (global.asx)

public static void Register(HttpConfiguration config)
{
    config.Filters.Add(new AuthorizeAttribute());
}

या प्रति नियंत्रक:

[Authorize]
public class ValuesController : ApiController{
...

निस्संदेह आपके प्रमाणीकरण का प्रकार भिन्न हो सकता है और आप अपना खुद का प्रमाणीकरण करना चाहेंगे, जब ऐसा होता है तो आपको प्राधिकृत विशेषता से उपयोगी विरासत मिल सकती है और इसे आपकी आवश्यकताओं को पूरा करने के लिए विस्तारित किया जा सकता है:

public class DemoAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (Authorize(actionContext))
        {
            return;
        }
        HandleUnauthorizedRequest(actionContext);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
        challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
        throw new HttpResponseException(challengeMessage);
    }

    private bool Authorize(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        try
        {
            var someCode = (from h in actionContext.Request.Headers where h.Key == "demo" select h.Value.First()).FirstOrDefault();
            return someCode == "myCode";
        }
        catch (Exception)
        {
            return false;
        }
    }
}

और आपके नियंत्रक में:

[DemoAuthorize]
public class ValuesController : ApiController{

WebApi प्राधिकरणों के लिए अन्य कस्टम लागू करने पर एक लिंक यहां दिया गया है:

http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/


मैं सर्विसस्टैक के बारे में वास्तव में बहुत कुछ नहीं कह सकता, लेकिन वेब एपीआई में बहुत सी शानदार विशेषताएं हैं और वर्तमान में संस्करण 2 पर हैं।

वेब एपीआई के साथ आप कुछ चीजें कर सकते हैं:

  • एक ओविन आवेदन में स्वयं होस्ट (यानी कहीं भी चलता है)।
  • async लिए पूर्ण समर्थन और await
  • अच्छे डिफ़ॉल्ट टेम्पलेट्स और खुले स्रोत उदाहरणों के टन।
  • प्रयुक्त महान जेसन.Net JSON serializer।
  • डिफ़ॉल्ट रूप से Rest-ish (आपको स्वयं को हाइपर्मिया करना होगा)।
  • और अधिक...




c# asp.net-mvc oauth asp.net-web-api