Joh*_*hnC 7 url-parameters jwt asp.net-core-mvc asp.net-core
我有一个受JWT和Authorize属性保护的api,在客户端,我使用jquery ajax调用来处理它。
这可以正常工作,但是我现在需要能够安全地下载文件,因此无法设置标头Bearer值,可以在URI中将其作为url参数吗?
=-=-=-=-
更新:这是我最终为自己的方案所做的事情,这是一个内部项目,数量很少,但是安全性很重要,将来可能需要扩展:
当用户登录时,我生成一个随机的下载密钥,并将其与JWT的到期日期一起放入数据库的用户记录中,然后将下载密钥返回给客户端。如果有一个具有下载密钥的查询参数,并且该密钥存在于用户记录中并且尚未过期,则下载路径受保护仅允许下载。这样,dl密钥对每个用户都是唯一的,只要用户的auth会话有效且可以轻松吊销,该密钥就有效。
这是一个普遍的问题。
每当您想直接从单个页面应用程序的HTML中的API引用图像或其他文件时,都无法Authorization在<img>or <a>元素和对该API 的请求之间注入请求标头。您可以通过使用此处所述的一些相当新的浏览器功能来回避此问题,但是您可能需要支持缺少此功能的浏览器。
幸运的是,RFC 6750通过“ URI查询参数”身份验证方法指定了一种完全按照您的要求进行操作的方法。如果遵循其约定,您将使用以下格式接受JWT:
https://server.example.com/resource?access_token=mF_9.B5f-4.1JqM&p=q
如另一个答案和RFC 6750本身所述,您应该仅在必要时这样做。从RFC:
由于与URI方法相关的安全性弱点(请参阅第5节),包括记录访问令牌的URL的可能性很高,因此,除非无法在“授权”中传输访问令牌,否则不应使用该URL。请求标头字段或HTTP请求实体正文。
如果您仍然决定实施“ URI查询参数”身份验证,则可以使用Invio.Extensions.Authentication.JwtBearer库和上的调用AddQueryStringAuthentication()扩展方法JwtBearerOptions。或者,如果您想手动执行此操作,当然也可以执行此操作。这是一个代码示例,将两种方式都显示为Microsoft.AspNetCore.Authentication.JwtBearer库的扩展。
public void ConfigureServices(IServiceCollection services) {
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(
options => {
var authentication = this.configuration.GetSection("Authentication");
options.TokenValidationParameters = new TokenValidationParameters {
ValidIssuers = authentication["Issuer"],
ValidAudience = authentication["ClientId"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(authentication["ClientSecret"])
)
};
// OPTION 1: use `Invio.Extensions.Authentication.JwtBearer`
options.AddQueryStringAuthentication();
// OPTION 2: do it manually
options.Events = new JwtBearerEvents {
OnMessageReceived = (context) => {
StringValues values;
if (!context.Request.Query.TryGetValue("access_token", out values)) {
return Task.CompletedTask;
}
if (values.Count > 1) {
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Fail(
"Only one 'access_token' query string parameter can be defined. " +
$"However, {values.Count:N0} were included in the request."
);
return Task.CompletedTask;
}
var token = values.Single();
if (String.IsNullOrWhiteSpace(token)) {
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Fail(
"The 'access_token' query string parameter was defined, " +
"but a value to represent the token was not included."
);
return Task.CompletedTask;
}
context.Token = token;
return Task.CompletedTask;
}
};
}
);
}
Run Code Online (Sandbox Code Playgroud)
尽管从技术上讲可以在URL中包含JWT,但强烈建议不要这样做。请参阅此处的引言,它解释了为什么这是一个坏主意:
不要在页面URL中传递承载令牌:不应在页面URL中传递承载令牌(例如,作为查询字符串参数)。相反,承载令牌应该在采取保密措施的HTTP消息头或消息主体中传递。浏览器,Web服务器和其他软件可能无法充分保护浏览器历史记录,Web服务器日志和其他数据结构中的URL。如果在页面URL中传递了承载令牌,则攻击者可能能够从历史数据,日志或其他不安全的位置中窃取它们。
但是,如果您别无选择或者只是不在乎安全性实践,请参阅Technetium的答案。
您可以使用中间件从查询参数中设置授权标头:
public class SecureDownloadUrlsMiddleware
{
private readonly RequestDelegate next;
public SecureDownloadUrlsMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context /* other dependencies */)
{
// get the token from query param
var token = context.Request.Query["t"];
// set the authorization header only if it is empty
if (string.IsNullOrEmpty(context.Request.Headers["Authorization"]) &&
!string.IsNullOrEmpty(token))
{
context.Request.Headers["Authorization"] = $"Bearer {token}";
}
await next(context);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在 Startup.cs 中使用身份验证中间件之前的中间件:
app.UseMiddleware(typeof(SecureDownloadUrlsMiddleware));
app.UseAuthentication();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3500 次 |
| 最近记录: |