如何保護ASP.NET Web API [關閉]

本文翻譯自:How to secure an ASP.NET Web API [closed]

I want to build a RESTful web service using ASP.NET Web API that third-party developers will use to access my application's data. 我想使用ASP.NET Web API構建RESTful Web服務,第三方開發人員將使用該服務訪問我的應用程序的數據。

I've read quite a lot about OAuth and it seems to be the standard, but finding a good sample with documentation explaining how it works (and that actually does work!) seems to be incredibly difficult (especially for a newbie to OAuth). 我已經閱讀了很多有關OAuth的文章 ,這似乎是標準的,但是要找到一個很好的示例來說明其工作原理(實際上是有效的!)的文檔似乎非常困難(尤其是對於使用OAuth的新手而言)。

Is there a sample that actually builds and works and shows how to implement this? 是否有一個實際構建和工作的示例,並顯示瞭如何實現此示例?

I've downloaded numerous samples: 我下載了許多示例:

  • DotNetOAuth - documentation is hopeless from a newbie perspective DotNetOAuth-從新手角度看文檔是沒有希望的
  • Thinktecture - can't get it to build Thinktecture-無法構建

I've also looked at blogs suggesting a simple token-based scheme (like this ) - this seems like re-inventing the wheel but it does have the advantage of being conceptually fairly simple. 我也看過博客,提出了一個基於令牌的簡單方案(像這樣 )-好像是在重新發明輪子,但是這樣做的確在概念上相當簡單。

It seems there are many questions like this on SO but no good answers. 在SO上似乎有很多類似問題,但沒有好的答案。

What is everybody doing in this space? 每個人在這個空間裏做什麼?


#1樓

參考:https://stackoom.com/question/nPMw/如何保護ASP-NET-Web-API-關閉


#2樓

Update: 更新:

I have added this link to my other answer how to use JWT authentication for ASP.NET Web API here for anyone interested in JWT. 我已將此鏈接添加到我的其他答案中, 如何在此爲對JWT感興趣的任何人對ASP.NET Web API使用JWT身份驗證


We have managed to apply HMAC authentication to secure Web API, and it worked okay. 我們已經設法將HMAC身份驗證應用於安全的Web API,並且工作正常。 HMAC authentication uses a secret key for each consumer which both consumer and server both know to hmac hash a message, HMAC256 should be used. HMAC身份驗證爲每個使用者使用一個祕密密鑰,使用者和服務器都知道該密鑰對hmac哈希消息,應該使用HMAC256。 Most of the cases, hashed password of the consumer is used as a secret key. 在大多數情況下,使用消費者的哈希密碼作爲祕密密鑰。

The message normally is built from data in the HTTP request, or even customized data which is added to HTTP header, the message might include: 該消息通常是根據HTTP請求中的數據甚至添加到HTTP標頭中的自定義數據構建的,該消息可能包括:

  1. Timestamp: time that request is sent (UTC or GMT) 時間戳:請求發送的時間(UTC或GMT)
  2. HTTP verb: GET, POST, PUT, DELETE. HTTP動詞:GET,POST,PUT,DELETE。
  3. post data and query string, 發佈數據和查詢字符串,
  4. URL 網址

Under the hood, HMAC authentication would be: 在後臺,HMAC身份驗證將是:

Consumer sends a HTTP request to web server, after building the signature (output of hmac hash), the template of HTTP request: 消費者在構建簽名(hmac哈希的輸出)後,將HTTP請求發送到Web服務器,該請求是HTTP請求的模板:

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

Example for GET request: GET請求的示例:

GET /webapi.hmac/api/values

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

The message to hash to get signature: 哈希以獲取簽名的消息:

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

Example for POST request with query string (signature below is not correct, just an example) 帶查詢字符串的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

The message to hash to get signature 散列消息以獲取簽名的消息

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

Please note that form data and query string should be in order, so the code on the server get query string and form data to build the correct message. 請注意,表單數據和查詢字符串應順序排列,因此服務器上的代碼將獲取查詢字符串和表單數據以構建正確的消息。

When HTTP request comes to the server, an authentication action filter is implemented to parse the request to get information: HTTP verb, timestamp, uri, form data and query string, then based on these to build signature (use hmac hash) with the secret key (hashed password) on the server. 當HTTP請求到達服務器時,將實施身份驗證操作過濾器以解析請求以獲取信息:HTTP動詞,時間戳,uri,表單數據和查詢字符串,然後基於這些信息構建帶有祕密的簽名(使用hmac哈希)服務器上的密鑰(哈希密碼)。

The secret key is got from the database with the username on the request. 祕密密鑰是從數據庫中獲得的,並帶有請求中的用戶名。

Then server code compares the signature on the request with the signature built; 然後,服務器代碼將請求上的簽名與構建的簽名進行比較; if equal, authentication is passed, otherwise, it failed. 如果相等,則認證通過,否則,認證失敗。

The code to build signature: 構建簽名的代碼:

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;
}

So, how to prevent replay attack? 那麼,如何防止重放攻擊?

Add constraint for the timestamp, something like: 爲時間戳添加約束,例如:

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

(servertime: time of request coming to server) (servertime:請求到達服務器的時間)

And, cache the signature of the request in memory (use MemoryCache, should keep in the limit of time). 並且,將請求的簽名緩存在內存中(使用MemoryCache,應保持時間限制)。 If the next request comes with the same signature with the previous request, it will be rejected. 如果下一個請求帶有與前一個請求相同的簽名,則它將被拒絕。

The demo code is put as here: https://github.com/cuongle/Hmac.WebApi 演示代碼如下所示: https : //github.com/cuongle/Hmac.WebApi


#3樓

Have you tried DevDefined.OAuth? 您是否嘗試過DevDefined.OAuth?

I have used it to secure my WebApi with 2-Legged OAuth. 我已使用它使用2-Legged OAuth保護我的WebApi。 I have also successfully tested it with PHP clients. 我也已經用PHP客戶端成功測試了它。

It's quite easy to add support for OAuth using this library. 使用此庫添加對OAuth的支持非常容易。 Here's how you can implement the provider for ASP.NET MVC Web API: 這是實現ASP.NET MVC Web API提供程序的方法:

1) Get the source code of DevDefined.OAuth: https://github.com/bittercoder/DevDefined.OAuth - the newest version allows for OAuthContextBuilder extensibility. 1)獲取DevDefined.OAuth的源代碼: https : //github.com/bittercoder/DevDefined.OAuth-最新版本允許OAuthContextBuilder擴展。

2) Build the library and reference it in your Web API project. 2)構建庫,並在您的Web API項目中引用它。

3) Create a custom context builder to support building a context from HttpRequestMessage : 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) Use this tutorial for creating an OAuth provider: http://code.google.com/p/devdefined-tools/wiki/OAuthProvider . 4)使用本教程創建OAuth提供程序: http : //code.google.com/p/devdefined-tools/wiki/OAuthProvider In the last step (Accessing Protected Resource Example) you can use this code in your AuthorizationFilterAttribute attribute: 在最後一步(訪問受保護的資源示例)中,可以在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()
            };
    }
}

I have implemented my own provider so I haven't tested the above code (except of course the WebApiOAuthContextBuilder which I'm using in my provider) but it should work fine. 我已經實現了自己的提供程序,所以我沒有測試上面的代碼(當然,我在提供程序中使用的WebApiOAuthContextBuilder除外),但是它應該可以正常工作。


#4樓

I would suggest starting with the most straightforward solutions first - maybe simple HTTP Basic Authentication + HTTPS is enough in your scenario. 我建議先從最簡單的解決方案開始-在您的情況下,簡單的HTTP基本身份驗證+ HTTPS可能就足夠了。

If not (for example you cannot use https, or need more complex key management), you may have a look at HMAC-based solutions as suggested by others. 否則(例如,您不能使用https,或者需要更復雜的密鑰管理),您可以看看其他人建議的基於HMAC的解決方案。 A good example of such API would be Amazon S3 ( http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html ) 此類API的一個很好的例子是Amazon S3( http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html

I wrote a blog post about HMAC based authentication in ASP.NET Web API. 我寫了一篇有關ASP.NET Web API中基於HMAC的身份驗證的博客文章。 It discusses both Web API service and Web API client and the code is available on bitbucket. 它討論了Web API服務和Web API客戶端,並且代碼在bitbucket上可用。 http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/ http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

Here is a post about Basic Authentication in Web API: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/ 這是有關Web API中基本身份驗證的文章: http : //www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

Remember that if you are going to provide an API to 3rd parties, you will also most likely be responsible for delivering client libraries. 請記住,如果您要向第三方提供API,則您很有可能負責交付客戶端庫。 Basic authentication has a significant advantage here as it is supported on most programming platforms out of the box. 基本身份驗證在此具有顯着的優勢,因爲大多數編程平臺都支持基本身份驗證。 HMAC, on the other hand, is not that standardized and will require custom implementation. 另一方面,HMAC尚未標準化,需要自定義實現。 These should be relatively straightforward but still require work. 這些應該相對簡單,但是仍然需要工作。

PS. PS。 There is also an option to use HTTPS + certificates. 還有一個使用HTTPS +證書的選項。 http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/ http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/


#5樓

If you want to secure your API in a server to server fashion (no redirection to website for 2 legged authentication). 如果要以服務器到服務器的方式保護API(不進行兩腿式身份驗證的網站重定向)。 You can look at OAuth2 Client Credentials Grant protocol. 您可以查看OAuth2客戶端憑據授予協議。

https://dev.twitter.com/docs/auth/application-only-auth https://dev.twitter.com/docs/auth/application-only-auth

I have developed a library that can help you easily add this kind of support to your WebAPI. 我開發了一個庫,可以幫助您輕鬆地將這種支持添加到WebAPI。 You can install it as a NuGet package: 您可以將其安裝爲NuGet軟件包:

https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0 https://nuget.org/packages/OAuth2ClientCredentialsGrant/1.0.0.0

The library targets .NET Framework 4.5. 該庫面向.NET Framework 4.5。

Once you add the package to your project, it will create a readme file in the root of your project. 將包添加到項目後,它將在項目的根目錄中創建一個自述文件。 You can look at that readme file to see how to configure/use this package. 您可以查看該自述文件,以瞭解如何配置/使用此軟件包。

Cheers! 乾杯!


#6樓

Web API introduced an Attribute [Authorize] to provide security. Web API引入了屬性[Authorize]以提供安全性。 This can be set globally (global.asx) 可以全局設置(global.asx)

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

Or per controller: 或每個控制器:

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

Of course your type of authentication may vary and you may want to perform your own authentication, when this occurs you may find useful inheriting from Authorizate Attribute and extending it to meet your requirements: 當然,您的身份驗證類型可能會有所不同,並且您可能希望執行自己的身份驗證,當這種情況發生時,您可能會發現從Authorizate Attribute繼承有用並擴展其以滿足您的要求:

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;
        }
    }
}

And in your controller: 在您的控制器中:

[DemoAuthorize]
public class ValuesController : ApiController{

Here is a link on other custom implemenation for WebApi Authorizations: 這是WebApi授權的其他自定義實現的鏈接:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章