Desarrollo seguro con aplicaciones de página única (SPA)
Al desarrollar sistemas distribuidos nativos de la nube, la protección de estos sistemas puede introducir un nuevo nivel de complejidad.
Los sistemas locales se basan en los límites de seguridad que proporciona la red interna y usan los servicios de directorio para la seguridad de los usuarios. Pueden ejecutarse durante muchos años en este entorno seguro sin problemas. El traslado a la nube puede presentar nuevos riesgos de seguridad. En este artículo se describen las herramientas que puede usar para mitigar estos riesgos.
Una de estas herramientas es el control de acceso. El control de acceso identifica a los usuarios y regula lo que pueden hacer al interactuar con una aplicación.
Hay dos partes para el control de acceso:
- La autenticación identifica al usuario.
- La autorización determina lo que el usuario puede hacer en la aplicación.
OAuth, un marco abierto, ayuda a abordar estos desafíos y proporciona un protocolo para que los desarrolladores los usen al compilar sus sistemas. OAuth 2.0 es el estándar actual.
OAuth 2.0 proporciona acceso delegado seguro. Mediante la emisión de tokens de acceso, puede autorizar el acceso de terceros a los recursos protegidos sin proporcionar credenciales.
Azure Active Directory (Azure AD) es la solución integrada de Microsoft para administrar identidades en la nube. Se integra con sistemas locales para que los usuarios tengan una experiencia sin problemas al acceder a los servicios de protección en la nube.
En esta guía se muestra cómo usar Azure AD o OAuth 2.0 para proteger una aplicación de página única.
Flujos de OAuth
Los flujos de OAuth cubren muchos casos de uso, todos ellos con el respaldo de Azure AD Services. Los desarrolladores usan estos flujos para crear una aplicación segura, de modo que:
- Los usuarios pueden acceder de forma segura a los sistemas cliente.
- Los usuarios invitados pueden participar a través de transacciones de negocio a negocio.
- Los usuarios pueden llegar a los consumidores finales a través de Azure Business to Consumers (Azure B2C).
Hay dos flujos de OAuth: concesión implícita y código de autorización. La concesión implícita es la más común, pero se recomienda usar el flujo de código de autorización.
Registro de la aplicación en Azure
Registre una entidad de servicio para la interfaz de usuario y la API con Azure AD Directory en Azure Portal.
Inicie sesión en Azure Portal y, a continuación, busque Registros de aplicaciones.
Seleccione Nuevo registro.
Para registrar una nueva aplicación, necesita:
- El nombre para mostrar de la aplicación.
- El tipo de cuenta admitido.
- El tipo de aplicación: web, SPA o cliente público o nativo (móvil y escritorio).
- El URI de redireccionamiento. Cuando se autentica el usuario, Azure AD redirige el resultado al cliente.
- Un ejemplo para el desarrollo local es http://localhost:4200.
- Un ejemplo para producción es "https://portal.contoso.com".
Seleccione Registrar.
Una vez completado el registro, seleccione Información general y, a continuación, seleccione el nombre de la aplicación junto a Aplicación administrada en el directorio local.
Seleccione Propiedades, cambie Asignación de usuario necesaria a Sí para establecer los permisos de acceso para la aplicación y, a continuación, seleccione Guardar.
Seleccione Usuarios y grupos y agregue usuarios y grupos de seguridad nuevos o existentes.
Los usuarios pueden acceder a la aplicación a través de Aplicaciones.
Configuración de los detalles de configuración en la aplicación cliente
Después de crear y configurar el registro de aplicaciones en Azure, puede configurar los detalles de configuración en la aplicación cliente. Para un marco de una sola página como Angular, Microsoft ha desarrollado la biblioteca @Azure/msal-angular para ayudarle a integrar Azure AD en la aplicación cliente.
Instale una biblioteca @Azure/msal-angular.
Configure la biblioteca.
protectedResourceMapcontiene una lista de recursos protegidos y sus ámbitos en una matriz: [[recurso protegido], [ámbitos para el recurso]].clientIDyauthority, que es el identificador de inquilino, se proporcionan al objeto de configuración.- Para las solicitudes HTTP protegidas, el cliente inserta una nueva propiedad de encabezado denominada Autorización. Contiene el token de portador para el usuario autenticado. El token de portador proporciona al servicio OAuth 2.0 de bajada un punto de entrada seguro. Puede incluir metadatos para el servicio al autorizar la solicitud.
export const protectedResourceMap: [string, string[]][]] = [
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['https://localhost:5001/api/weatherforecast', ['api://ae05da8f-07d0-4ae6-aef1-18a6af68e5dd/access_as_user']]
];
function MSALConfigFactory(): Configuration {
return {
auth: {
clientId: 'eba23c0b-1e86-4f68-b1d2-9c54d96083de',
authority: 'https://login.microsoftonline.com/1c302616-bc6a-45a6-9c07-838c89d55003',
redirectUri: 'http://localhost:4200',
validateAuthority: true,
postLogoutRedirectUri: 'http://localhost:4200',
navigateToLoginRequestUrl: true
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false //set to false, not ie 11
}
};
}
Para obtener más información sobre cómo configurar una biblioteca Angular, consulte Tutorial: Inicio de sesión de usuarios y llamada a Microsoft Graph API desde una aplicación de página única (SPA) de Angular mediante el uso del flujo de código de autenticación.
Prueba de la autenticación de la aplicación
Para probar el proceso de autenticación, haga que un usuario con acceso y un usuario sin acceso intenten iniciar sesión en el cliente.
El usuario inicia sesión en la aplicación y se redirige a su inquilino de Azure AD.
- Si el usuario es válido, se autentica y se inicia sesión.
- Si el usuario no es válido, la aplicación devuelve un error.
Consumo de un servidor de recursos o recursos protegidos
Para consumir un recurso protegido, cree otro registro de aplicación. Una vez completado el registro de aplicación, la API cambia el token de portador para permitir el acceso.
Exposición de la API
Cree otro registro de aplicación en Azure.
Seleccione Exponer una API y, a continuación, seleccione Agregar un ámbito.
Escriba el URI de id. de aplicación y, a continuación, seleccione Guardar y continuar. La API usa este permiso para validar la solicitud.
Configure el nombre del ámbito y la información de consentimiento. Si selecciona Solo administradores, solo los administradores pueden conceder consentimiento para el directorio.
Adición de la API al registro de aplicación
Ahora que ha definido los permisos y expuesto la API, debe agregar la API al registro de la aplicación para el cliente.
En el registro de aplicación, seleccione Permisos de la API y, luego, Agregar un permiso.
Seleccione Mis API y, a continuación, seleccione el registro de API que ha creado.
Seleccione el ámbito que creó para exponer el permiso de API y, a continuación, seleccione Agregar permisos.
Ahora la API está agregada a la aplicación. Puesto que es posible que tenga que volver a conceder consentimiento para acceder a la API, considere la posibilidad de conceder el consentimiento del administrador para que los usuarios no tengan que volver a dar su consentimiento.
Adición de la API a la asignación de recursos protegidos
Ahora que la configuración de Azure Portal está completa, el cliente de la interfaz de usuario puede consumir el recurso. Agregue la API a la asignación de recursos protegidos para asegurarse de que la interfaz de usuario adjunta el token de portador correcto para la solicitud de API.
export const protectedResourceMap: [string, string[]][] = [
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['https://localhost:5001/api/weatherforecast', ['api://eba23c0b-1e86-4f68-b1d2-9c54d96083de/access_as_user']]
];
Cuando la aplicación cliente intenta acceder al recurso, la biblioteca cliente de MSAL se autentica en Azure AD a través de un iframe oculto y, a continuación, devuelve un token de portador para el recurso. El token de portador solo se agrega para las solicitudes que coinciden con el punto de conexión, en este caso https://localhost:5001/api/weatherforecast.
Si la API que configuró con los registros de aplicaciones pertinentes recibe un token de portador con un URI de id. de aplicación no válido, rechaza la solicitud y devuelve un mensaje 401 no autorizado.
En el ejemplo siguiente, el servicio back-end se escribe en .NET Core. En el ejemplo se muestran las propiedades de configuración de la API. ClientId tiene el URI de id. de aplicación en el formato de api://{clientId}.
"AzureAD": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "yourName.onmicrosoft.com",
"TenantId": "1c302616-bc6a-45a6-9c07-838c89d55003",
"ClientId": "api://ae05da8f-07d0-4ae6-aef1-18a6af68e5dd"
},
Dentro de la clase de inicio de la API de .NET Core, el esquema de autenticación y las opciones se agregan al método de configuración de servicios.
services.Addauthentication(AzureADDefaults.BearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAD",
options));
Cuando el cliente llama a la API, el token de portador se agrega a la solicitud.
Puede ir a jwt.ms y pegar el token de portador en un formato legible.
Puede ver que el URI de API está dentro de la propiedad aud. Esta propiedad identifica el destinatario previsto del token, que es la API. Si la API no es el destinatario previsto, rechaza automáticamente la solicitud con una respuesta HTTP 401.
La propiedad scp contiene el conjunto de ámbitos expuestos por la aplicación. Si se agregan ámbitos no válidos a través del cliente, Azure AD devuelve un error que solicita una autorización adicional para el ámbito.
Uso del manifiesto de aplicación para definir aún más la autorización
Otras prácticas de autorización se implementan mediante el manifiesto de aplicación para el registro de aplicación de API. Puesto que ha definido explícitamente usuarios, puede agregar más niveles de autorización y permitir que los miembros de un grupo de seguridad específico accedan a recursos más confidenciales.
En el registro de aplicación, seleccione Manifiesto.
Edite los pares clave-valor del objeto JSON según sea necesario.
En general, es mejor emitir solo SecurityGroup. Si usa All, se emiten grupos de seguridad, roles de Azure AD y grupos de distribución. El token tiene un límite establecido de 200 y, si se alcanza ese límite, se agrega una notificación de uso por encima del límite. La notificación apunta al punto de conexión de Graph para recuperar la lista de grupos para el usuario.
Después de la configuración, el token jwt tiene una nueva propiedad, groups, que contiene los identificadores de objeto únicos que se pueden usar para aplicar la autorización.
La API se puede configurar con una directiva que busca una notificación y un valor necesarios para la autorización basada en roles a través del controlador de directivas.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAD",
options));
services.AddAuthorization(options =>
{
options.AddPolicy("DensuAegisReportsAdmin", policyBuilder =>
{
policyBuilder.RequireClaim("groups", "ebde25e7-d254-474e-ae33-cd491aa98ebf"); //This would be an environment variable
});
});
JWTSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddCors();
services.AddControllers();
}
El controlador de la API puede tener agregadas las atribuciones pertinentes. Estos atributos ofrecen más seguridad y ayudan a confirmar que las personas autenticadas están autorizadas para acceder al recurso protegido.
[Route("admin")]
[Authorize("DensuAegisReportsAdmin")]
public IActionResult GetForcastsForAdmin()
{
var user = User.Claims;
var groups = User.Claims.Where(c => c.Type == "groups").Select(c => c.Value).ToList();
var userName = UserClaims.Where(c => c.Type == "unique_name").Select(c => c.Value).FirstOrDefault();
// SecurityGroup = groups
var rng = new Random();
var forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)],
})
.ToArray();
return Ok(new
{
User = userName
,
SecurityGroup = groups
,
Forcasts = forecasts
});
}
Se pueden crear más roles con el manifiesto de aplicación que son únicos para el registro de aplicación. A continuación, se pueden crear más grupos en el contexto de la aplicación.
Por ejemplo, puede crear un rol personalizado denominado AppAdmin que sea único para el registro de aplicación. Con la compilación de la aplicación empresarial, puede asignar usuarios o grupos de seguridad a ese rol.
Cuando se llama al recurso protegido después del cambio de configuración, el token de portador tiene la propiedad roles dentro del token de portador.
La API se configura mediante el generador de directivas en Configurar servicios.
// Adding authorization policies that enforce authorization using Azure AD roles.
services.AddAuthorization(options =>
{
options.AddPolicy(AuthorizationPolicies.AssignmentToAppAdminRoleRequired, policy =>
policy.RequireRole(AppRole.AppAdmin));
});
La ruta protegida usa la directiva de autorización para asegurarse de que el usuario autenticado está en el rol pertinente antes de autorizar la solicitud.
Pasos siguientes
- Integración de dominios de AD locales con Azure Active Directory
- Administración de identidades y acceso de Azure Active Directory para AWS
- Implementación de AD DS en una red virtual de Azure