如何保护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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值