Http Only Cookie保護AccessToken

前言

JWT認證方式目前已被廣泛使用,一直以來我們將token放在請求頭中的Authorization中,若通過此種方式,一旦token被惡意竊取,攻擊者可肆意對用戶可訪問資源進行任意索取,我們大多都是通過登錄成功後,響應AccessToken,然後由前端將token存儲在相關Storage中,然後每次將其放請求頭而認證請求,由於token是極其敏感信息,所以我們不能將其交由前端去處理,而應由後臺獲取對前端不可見。對安全有較高要求的平臺,我們通過Http Only Cookie來解決token惡意竊取問題

Http Only Cookie

Http Only Cookie簡言之則是將相關信息響應時存儲在Cookie中,而客戶端腳本無法訪問,每次請求時,則將自動攜帶所有信息到服務器。例如,京東存儲相關信息

接下來我們看看在.NET Core中如何將AccessToken以Http Only方式存儲在Cookie中

[AllowAnonymous]
[HttpGet("api/test/get")]
public IActionResult Get()
{
    Response.Cookies.Append("x-access-token", GenerateToken(),
      new CookieOptions()
      {
        Path = "/",
        HttpOnly = true
      });

    return Ok();
}

如上,我們模擬登錄成功,並不返回AccessToken,而是將其寫入到響應頭中,上述Cookie選項HttpOnly爲true即表示客戶端腳本不可訪問

此時我們來訪問如下需認證接口

[HttpGet("api/test/say")]
public string Say()
{
   return "Hello World";
}

用過JWT的童鞋都知道,標準模式則是將AccessToken寫入到Authorization中,即請求頭【Authorization: Bearer ......】,那麼上述是如何認證成功而請求到接口的呢?當我們添加JWT認證時,每次請求在其對應事件OnMessageReceived中將自動獲取請求頭Authorization中的值,將其賦值給context.Token

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
   ......
   options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
          //Bearer Token
          context.Token = "";  
          return Task.CompletedTask;
        }
    };
});

你問我是怎麼知道的,我是猜的嗎,當然不是,丟出官方源碼就知道了,直接找到JWT如何處理認證則一目瞭然

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
    string token = null;

    // Give application opportunity to find from a different location, adjust, or reject token
    var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options);

    // event can set the token
    await Events.MessageReceived(messageReceivedContext);
    if (messageReceivedContext.Result != null)
    {
      return messageReceivedContext.Result;
    }

    // If application retrieved token from somewhere else, use that.
    token = messageReceivedContext.Token;

    if (string.IsNullOrEmpty(token))
    {
      string authorization = Request.Headers[HeaderNames.Authorization];

      // If no authorization header found, nothing to process further
      if (string.IsNullOrEmpty(authorization))
      {
        return AuthenticateResult.NoResult();
      }
    }
   ....... 
}

到這裏我們知道了自動獲取Token的原理,我們修改了Token存儲方式,照葫蘆畫瓢就好,如此將覆蓋默認標準模式,如下:

OnMessageReceived = context =>
{
   var accessToken = context.Request.Cookies["x-access-token"];

   if (!string.IsNullOrEmpty(accessToken))
   {
      context.Token = accessToken;
   }

   return Task.CompletedTask;
}

從分析自動獲取Token原理,我們也可知道,若與第三方對接,依然可以使用請求頭Authorization標準模式認證,因爲Cookie爲空,再次獲取Authorization值。注意:發現若將前端未置於wwwroot下,即完全前後分離,涉及到跨域的情況下,比如使用的是axios封裝請求,那麼應該必須在請求頭中添加【withCredentials:true 】,否則使用Http Only將無效,出現401

 

額外意外發現一個很有意思的問題,未深入研究,這裏當做小知識瞭解下就好,或許是我自以爲發現新大陸了呢。

 

當我們創建AccessToken時,都會設置一個過期時間,我們知道此過期時間肯定不會設置過長,但是若在比如移動端微信小程序中,若設置時間不長,必然要考慮刷新Token問題,爲了懶一點,我們將Token設置爲永不過期,那麼JWT支持嗎?

 

當然支持,只不過根據我剛好嘗試了幾次,找到了JWT永不過期的上限,最大隻能是16年,若超過此臨界點,比如17年,如下:

將會出現401,具體錯誤如下:

總結

好了,本節我們暫時討論到這裏,再會啦~~~~ 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章