Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 微服务安全_C#_Microservices - Fatal编程技术网

C# 微服务安全

C# 微服务安全,c#,microservices,C#,Microservices,在过去的几天里,我一直在玩微服务模式,一切都很顺利,但安全性似乎让我感到困惑 因此,如果我可以问一个问题: 如何处理单个服务上的用户身份验证?此时,我将请求传递给网关API,该API依次连接到服务。 问题已编辑,请参见下文 请记住,各服务不应相互了解。网关本身就是聚合器 当前架构。 一个模拟请求的小代码: 前端-客户端应用程序 public class EntityRepository<T> { private IGateway _gateway = null;

在过去的几天里,我一直在玩微服务模式,一切都很顺利,但安全性似乎让我感到困惑

因此,如果我可以问一个问题: 如何处理单个服务上的用户身份验证?此时,我将请求传递给
网关API
,该API依次连接到服务。

问题已编辑,请参见下文

请记住,各服务不应相互了解。网关本身就是聚合器

当前架构。

一个模拟请求的小代码:

前端-客户端应用程序

public class EntityRepository<T>
{
    private IGateway _gateway = null;
    public EntityRepository(IGateway gateway)
    {
        this._gateway = gateway;
    }
    public IEnumerable<T> FindAll()
    {
        return this._gateway.Get(typeof(T)).Content.ReadAsAsync<IEnumerable<T>>().Result;
    }
    public T FindById(int id)
    {
        return this._gateway.Get(typeof(T)).Content.ReadAsAsync<T>().Result;
    }
    public void Add(T obj)
    {
        this._gateway.Post(typeof(T), obj);
    }
    public void Update(T obj)
    {
        this._gateway.Post(typeof(T), obj);
    }
    public void Save(T obj)
    {
        this._gateway.Post(typeof(T), obj);
    }
}


   //Logic lives elsewhere
   public HttpResponseMessage Get(Type type)
   {
      return Connect().GetAsync(Path(type)).Result;
   }
   public HttpResponseMessage Post(Type type, dynamic obj)
   {
      return Connect().PostAsync(Path(type), obj);
   }
    private string Path(Type type)
    {
        var className = type.Name;
        return "api/service/" + Application.Key + "/" + className;
    }
    private HttpClient Connect()
    {
        var client = new HttpClient();
        client.BaseAddress = new Uri("X");

        // Add an Accept header for JSON format.
         client.DefaultRequestHeaders.Accept.Add(
         new MediaTypeWithQualityHeaderValue("application/json"));

        return client;
    }
网关不包含这些类型的物理文件/类

在编写了一段代码之后,我希望有人能给我一点演示,或者是用当前架构处理安全/用户身份验证的最佳方法

案例场景1 用户点击web应用并登录,此时,用户加密的电子邮件和密码被发送到
网关API
,然后被传递到
用户服务
,并决定用户是否经过身份验证-一切正常,但现在我想从用户收到的
消息服务
获取所有消息。在网关中,如果用户经过身份验证,我不能真正说是否获取消息,因为这不能解决在
网关API
之外调用
消息服务
的问题

我也不能向每个单独的服务添加身份验证,因为这将需要所有相应的服务与
用户服务
进行通信,这会破坏模式的目的

修复: 仅允许网关调用服务。应阻止对网关外部服务的请求

我知道安全是一个广泛的话题,但在当前的背景下,我希望有人能指导我采取最佳行动来解决这个问题

目前,我已在所有非应用程序中硬编码了一个
Guid
,如果应用程序相等,则反过来获取数据。

选项1(首选)

简单的方法是微服务应该位于网关后面,因此您可以将服务列为白名单以连接到它们,这意味着只有授权和受信任的方可以访问(即仅网关)。客户不应该直接访问它们。大门是你的夜总会保镖

选项2

您可以使用JWT或某种形式的令牌,并在服务之间共享密钥。我使用JWT授权承载令牌

其他服务不需要查询用户服务,它们只需要知道令牌是有效的,然后它们就有权使用API。我将JWT从客户端传递到网关,并将其注入到发送到后面的另一个服务的请求中,只需直接传递

后面的微服务需要与网关具有相同的JWT消耗以进行授权,但正如我所提到的,它只是确定有效令牌,而不是查询有效用户

但这有一个问题,即一旦某人获得授权,他们就可以跳转调用其他用户的数据,除非您在令牌中包含类似于声明的内容

我的想法

我发现,从单一服务到微型服务的挑战在于,您需要切换信任的位置。在这里,你控制着你所负责的一切。微服务的要点是其他服务完全控制其域。您必须信任其他服务以履行其义务,而不希望在每一个级别上都重新检查并重新授权所有必要的内容。

Edit

这个答案是关于网关微服务通信的。当应用程序与网关对话时,用户当然应该得到正确的身份验证

结束编辑

首先,微型服务不应该从互联网上获得。它们应该只能从网关(可以群集)访问

其次,您确实需要能够识别当前用户。您可以通过将
UserId
作为HTTP头传递来实现。创建一个WebApi筛选器,该筛选器接受该头并从中创建一个自定义
IPrincipal

最后,您需要某种方法来确保请求来自网关或其他微服务。一种简单的方法是对令牌使用HMAC身份验证

将每个服务和网关的密钥存储在
web.config
中。然后只需在每个请求中发送一个令牌(您可以使用WebApi身份验证过滤器进行身份验证)

要生成哈希,请使用.NET中的
HMACSHA256
类:

private static string CreateToken(string message, string secret)
{
    secret = secret ?? "";
    var keyByte = Encoding.ASCII.GetBytes(secret);
    var messageBytes = Encoding.ASCII.GetBytes(message);
    using (var hasher = new HMACSHA256(keyByte))
    {
        var hashmessage = hasher.ComputeHash(messageBytes);
        return Convert.ToBase64String(hashmessage);
    }
}
因此,在您的
MicroServiceClient
中,您可以执行以下操作:

var hash = CreateToken(userId.ToString(), mySharedSecret);
var myHttpRequest = HttpRequest.Create("yourUrl");
myHttpRequest.AddHeader("UserId", userId);
myHttpRequest.AddHeader("UserIdToken", hash);
//send request..
在micro服务中,您可以创建一个过滤器,如:

public class TokenAuthenticationFilterAttribute : Attribute, IAuthenticationFilter
{
    protected string SharedSecret
    {
        get { return ConfigurationManager.AppSettings["SharedSecret"]; }
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        await Task.Run(() =>
        {
            var userId = context.Request.Headers.GetValues("UserId").FirstOrDefault();
            if (userId == null)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }

            var userIdToken = context.Request.Headers.GetValues("UserIdToken").FirstOrDefault();
            if (userIdToken == null)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }

            var token = CreateToken(userId, SharedSecret);
            if (token != userIdToken)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }


            var principal = new GenericPrincipal(new GenericIdentity(userId, "CustomIdentification"),
                new[] {"ServiceRole"});
            context.Principal = principal;
        });
    }

    public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
    }

    public bool AllowMultiple
    {
        get { return false; }
    }

    private static string CreateToken(string message, string secret)
    {
        secret = secret ?? "";
        var keyByte = Encoding.ASCII.GetBytes(secret);
        var messageBytes = Encoding.ASCII.GetBytes(message);
        using (var hasher = new HMACSHA256(keyByte))
        {
            var hashmessage = hasher.ComputeHash(messageBytes);
            return Convert.ToBase64String(hashmessage);
        }
    }
}

关于身份验证和授权有成千上万的问题,你的研究表明了什么?当然,任何静态的(比如GUID)都是不安全的,因为有人可以从网络流量中嗅探GUID并构建自己的应用程序,该应用程序也会发送相同的GUID。我非常熟悉单一应用程序中的身份验证和授权。该体系结构带来了挑战。您以前实现过微服务体系结构吗?Guid方法是临时的。您是否需要对客户端(应用程序)或资源所有者进行身份验证?当您不想限制对部分资源的访问时,客户端身份验证的含义是什么?您使用微服务实现服务与您的客户端无关。您的客户机看到的只是网关,因此他们根据网关进行身份验证。或者你的意思是网关是透明的,并且它背后的每个服务都有自己的身份验证和授权吗
public class TokenAuthenticationFilterAttribute : Attribute, IAuthenticationFilter
{
    protected string SharedSecret
    {
        get { return ConfigurationManager.AppSettings["SharedSecret"]; }
    }

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        await Task.Run(() =>
        {
            var userId = context.Request.Headers.GetValues("UserId").FirstOrDefault();
            if (userId == null)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }

            var userIdToken = context.Request.Headers.GetValues("UserIdToken").FirstOrDefault();
            if (userIdToken == null)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }

            var token = CreateToken(userId, SharedSecret);
            if (token != userIdToken)
            {
                context.ErrorResult = new StatusCodeResult(HttpStatusCode.Forbidden, context.Request);
                return;
            }


            var principal = new GenericPrincipal(new GenericIdentity(userId, "CustomIdentification"),
                new[] {"ServiceRole"});
            context.Principal = principal;
        });
    }

    public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
    {
    }

    public bool AllowMultiple
    {
        get { return false; }
    }

    private static string CreateToken(string message, string secret)
    {
        secret = secret ?? "";
        var keyByte = Encoding.ASCII.GetBytes(secret);
        var messageBytes = Encoding.ASCII.GetBytes(message);
        using (var hasher = new HMACSHA256(keyByte))
        {
            var hashmessage = hasher.ComputeHash(messageBytes);
            return Convert.ToBase64String(hashmessage);
        }
    }
}