Как защитить веб-API ASP.NET [закрыто]

0.01 не является целым числом (целым числом), поэтому вы, конечно, не можете его разобрать. Вместо этого используйте Double.parseDouble или Float.parseFloat.

378
задан Hossein Narimani Rad 29 April 2015 в 08:11
поделиться

6 ответов

Я бы предложил сначала начать с самых простых решений - возможно, в вашем сценарии достаточно простой базовой аутентификации HTTP + HTTPS.

Если нет (например, вы не можете использовать https или нуждаетесь в более сложном управлении ключами), вы можете взглянуть на решения на основе HMAC, как это предлагают другие. Хорошим примером такого API был бы Amazon S3 ( http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html )

Я написал сообщение в блоге. об аутентификации на основе HMAC в ASP.NET Web API. В нем рассматриваются как служба веб-API, так и клиент веб-API, а код доступен на bitbucket. http://www.piotrwalat.net/hmac-authentication-in-asp-net-web-api/

Вот пост о базовой аутентификации в веб-API: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/

Помните, что если вы собираетесь предоставить API для третьих лиц, вы также, скорее всего, будете нести ответственность за доставку клиентских библиотек. Базовая аутентификация имеет существенное преимущество, поскольку она поддерживается на большинстве программных платформ из коробки. HMAC, с другой стороны, не настолько стандартизирован и потребует индивидуальной реализации. Они должны быть относительно простыми, но все же требуют работы.

PS. Также есть возможность использовать HTTPS + сертификаты. http://www.piotrwalat.net/client-certificate-authentication-in-asp-net-web-api-and-windows-store-apps/

30
ответ дан Mike Hofer 29 April 2015 в 08:11
поделиться

Вы пробовали DevDefined.OAuth?

Я использовал его, чтобы защитить свой WebApi с помощью 2-Legged OAuth. Я также успешно протестировал его с PHP-клиентами.

С помощью этой библиотеки довольно легко добавить поддержку OAuth. Вот как вы можете реализовать провайдер для ASP.NET MVC Web API:

1) Получить исходный код DevDefined.OAuth: https://github.com/bittercoder/DevDefined.OAuth - новейшая версия обеспечивает расширяемость OAuthContextBuilder.

2) Создайте библиотеку и сделайте ссылку на нее в своем проекте Web API.

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) Используйте это руководство для создания поставщика OAuth: http://code.google .com / р / devdefined-инструменты / вики / 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, который я использую в своем провайдере), но он должен работать нормально.

23
ответ дан Maksymilian Majer 29 April 2015 в 08:11
поделиться

Обновление:

Я добавил эту ссылку к своему другому ответу , как использовать аутентификацию JWT для ASP.NET Web API здесь для всех, кто интересуется JWT.


Нам удалось применить аутентификацию HMAC для защиты веб-API, и все заработало нормально. HMAC-аутентификация использует секретный ключ для каждого потребителя, который, как пользователь, так и сервер, знают, что hmac хэширует сообщение, следует использовать HMAC256. В большинстве случаев хешированный пароль потребителя используется в качестве секретного ключа.

Сообщение обычно строится из данных в запросе HTTP или даже из настроенных данных, которые добавляются в заголовок HTTP, сообщение может включать в себя:

  1. Метка времени: время отправки запроса (UTC или GMT)
  2. HTTP-глагол: GET, POST, PUT, DELETE.
  3. отправлять данные и строку запроса,
  4. URL

Под капотом аутентификация HMAC будет:

Потребитель отправляет HTTP-запрос на веб-сервер после того, как построение подписи (вывод хеша hmac), шаблон HTTP-запроса:

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

Пример для запроса GET:

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-глагол, временная метка, uri, данные формы и строка запроса, а затем на их основе создается подпись (используется хэш hmac) с секретным ключом (хешированным паролем) на сервере.

Секретный ключ получен из базы данных с именем пользователя по запросу.

Затем серверный код сравнивает подпись по запросу с созданной подписью; если равно, аутентификация пройдена, в противном случае она не удалась.

Код для создания подписи:

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 

(время сервера: время поступления запроса на сервер)

И, кешировать подпись запроса в памяти (используйте MemoryCache, следует ограничить время). Если следующий запрос приходит с той же подписью, что и предыдущий, он будет отклонен.

Демонстрационный код приведен здесь: https://github.com/cuongle/Hmac.WebApi

282
ответ дан Trevor Reid 29 April 2015 в 08:11
поделиться

В Web API появился атрибут [Authorize] для обеспечения безопасности. Это может быть установлено глобально (global.asx)

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

Или для контроллера:

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

Конечно, ваш тип аутентификации может отличаться, и вы можете захотеть выполнить свою собственную аутентификацию, когда это происходит, вы можете найти полезное наследование от атрибута Authorizate и расширение его для удовлетворения ваших требований:

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/

20
ответ дан gligoran 29 April 2015 в 08:11
поделиться

Если вы хотите защитить свой API-интерфейс в режиме «сервер-сервер» (нет переадресации на веб-сайт для двухсторонней аутентификации). Вы можете посмотреть протокол OAuth2 Client Credentials Grant.

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

Я разработал библиотеку, которая поможет вам легко добавить такую ​​поддержку Ваш WebAPI. Вы можете установить его как пакет NuGet:

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

Библиотека предназначена для .NET Framework 4.5.

Как только вы добавите пакет в ваш проект, он создаст файл readme в корне вашего проекта. Вы можете посмотреть этот файл readme, чтобы увидеть, как настроить / использовать этот пакет.

Ура!

6
ответ дан Varun Chatterji 29 April 2015 в 08:11
поделиться

в продолжение ответа @ Cuong Le, мой подход к предотвращению повторной атаки будет следующим:

// Шифрование времени Unix на стороне клиента с использованием общего закрытого ключа (или пароля пользователя)

// Отправить его как часть заголовка запроса на сервер (WEB API)

// Расшифровать Unix Time at Server (WEB API), используя общий закрытый ключ (или пароль пользователя)

/ / Проверьте разницу во времени между временем Unix клиента и временем Unix сервера, не должна превышать x сек.

// если идентификатор пользователя / хэш-пароль верны и дешифрованный UnixTime находится в пределах x сек времени сервера, то это действительный запрос

2
ответ дан refactor 29 April 2015 в 08:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: