iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0

隨著 API 在現代應用程式中的使用日益普及,API 安全性成為開發者不可忽視的重要課題。當你開發一個公開的 API 時,確保其安全性是至關重要的。今天,我們將深入探討 API 的幾種常見保護方式,包括 API KeyOAuth 2.0、以及 JWT(JSON Web Token),並介紹如何使用這些方法來防止未授權的訪問與攻擊。


為什麼要保護 API?

API 是應用程式與外部系統的交互接口,經常處理著敏感數據和關鍵業務邏輯。未妥善保護的 API 可能面臨數據洩露、未授權訪問、DDoS 攻擊等風險。因此,保護 API 是確保系統穩定性、數據安全和用戶隱私的必要措施。


API 防護的常見方法


1. API Key

API Key 是最簡單且常見的 API 保護方式。每個使用 API 的用戶都會獲得一個唯一的 API Key,當用戶發送請求時,必須將此密鑰附加到請求的 Header 或 URL 中。伺服器會檢查該 Key 是否有效,並決定是否允許請求。

範例程式碼(.NET Core):

[ApiController]
[Route("api/[controller]")]
public class ProtectedController : ControllerBase
{
    private const string ApiKey = "my-secure-api-key";

    [HttpGet]
    public IActionResult GetProtectedResource([FromHeader(Name = "X-API-Key")] string apiKey)
    {
        if (apiKey != ApiKey)
        {
            return Unauthorized("API Key 無效");
        }
        return Ok("成功獲取保護的資源!");
    }
}

優點

  • 簡單易於實現。
  • 適合小型應用或低安全需求場景。

缺點

  • 安全性較低,API Key 容易洩露或分享。
  • 無法細緻地控制用戶權限。

2. OAuth 2.0

OAuth 2.0 是一個更為強大且安全的授權框架,特別適用於需要與第三方應用整合的場景。它允許應用程式在不需要用戶密碼的情況下,安全地訪問用戶的受保護資源。

OAuth 2.0 工作原理

OAuth 2.0 主要使用「授權碼流程」(Authorization Code Flow),流程如下:

  1. 用戶通過瀏覽器授權第三方應用訪問其資源。
  2. 第三方應用將授權請求發送給授權伺服器。
  3. 授權伺服器驗證後返回授權碼(Authorization Code)。
  4. 應用使用授權碼向授權伺服器請求 Access Token。
  5. 應用使用 Access Token 訪問受保護的 API 資源。

範例程式碼展示 OAuth 2.0 授權流程

以下範例展示了如何使用 OAuth 2.0 從 Google 授權伺服器獲取 Access Token,並使用該 Token 訪問 Google API。

[HttpGet("login")]
public IActionResult Login()
{
    string clientId = "your-client-id";
    string redirectUri = "<https://your-app.com/oauth2/callback>";
    string scope = "<https://www.googleapis.com/auth/userinfo.profile>";
    string state = "random_string"; // 防止CSRF攻擊
    string authUrl = $"<https://accounts.google.com/o/oauth2/v2/auth?client_id={clientId}&redirect_uri={redirectUri}&response_type=code&scope={scope}&state={state}>";

    return Redirect(authUrl);
}

[HttpGet("oauth2/callback")]
public async Task<IActionResult> OAuthCallback(string code, string state)
{
    // 檢查 state 防止 CSRF 攻擊
    if (string.IsNullOrEmpty(code))
    {
        return BadRequest("未能取得授權碼");
    }

    string tokenUrl = "<https://oauth2.googleapis.com/token>";
    var client = new HttpClient();
    var postData = new Dictionary<string, string>
    {
        { "code", code },
        { "client_id", "your-client-id" },
        { "client_secret", "your-client-secret" },
        { "redirect_uri", "<https://your-app.com/oauth2/callback>" },
        { "grant_type", "authorization_code" }
    };

    var response = await client.PostAsync(tokenUrl, new FormUrlEncodedContent(postData));
    var responseContent = await response.Content.ReadAsStringAsync();
    var tokenResponse = JsonConvert.DeserializeObject<OAuthTokenResponse>(responseContent);

    return Ok(tokenResponse);
}


3. JWT(JSON Web Token)

JWT 是一種廣泛使用的身份驗證技術,它將身份驗證和授權信息打包成一個自包含的 Token。JWT 是由三部分組成的:HeaderPayloadSignature,這些部分經過編碼後生成 Token,並可以攜帶用戶的身份信息,這使得系統在多次請求中不必每次查詢數據庫即可驗證身份。

JWT 工作原理

  1. 用戶登入並獲取 JWT:當用戶成功登入後,伺服器生成一個 JWT,並將其發送給用戶。

  2. 使用 JWT 發送請求:用戶將該 JWT 附加到後續 API 請求的 Authorization Header 中,形式如下:

    Authorization: Bearer <JWT>
    
    
  3. 伺服器驗證 JWT:伺服器解析並驗證 JWT,確認其合法性。如果 JWT 有效,請求將被授權繼續,否則返回未授權的錯誤。

JWT 組成部分

  1. Header:指定 Token 的類型(typ)和使用的簽名算法(alg)。

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
    
  2. Payload:包含聲明(claims),例如用戶 ID、角色或其他信息。

    {
      "sub": "1234567890",
      "name": "John Doe",
      "admin": true
    }
    
    
  3. Signature:使用密鑰來對 Header 和 Payload 進行簽名,保證 Token 的完整性。

    HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
    
    

JWT 實現範例

下面展示了如何在 .NET Core 中使用 JWT 來保護 API。

步驟 1: 配置 JWT 驗證

Startup.cs 中配置 JWT Bearer 身份驗證,設置 Token 驗證參數:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidAudience = Configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
        });

    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    // 啟用身份驗證
    app.UseAuthentication();

    // 啟用授權
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

步驟 2: 生成 JWT Token

使用 TokenService 來生成 JWT,當用戶成功登入後返回給用戶:

public class TokenService
{
    private readonly IConfiguration _configuration;

    public TokenService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GenerateToken()
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _configuration["Jwt:Issuer"],
            audience: _configuration["Jwt:Audience"],
            expires: DateTime.Now.AddMinutes(30),
            signingCredentials: credentials
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

步驟 3: 使用 Authorize 屬性來保護 API

有了 JWT 驗證配置後,我們可以使用 [Authorize] 屬性來保護 API 路由,確保只有攜帶有效 JWT Token 的請求才能訪問受保護的資源。

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class JwtController : ControllerBase
{
    [HttpGet]
    public IActionResult GetProtectedData()
    {
        return Ok("你已成功通過 JWT 驗證,獲取到保護的數據!");
    }
}


JWT 的優點

  • 自包含信息:JWT 包含了所有身份和授權信息,伺服器不需要存儲用戶狀態,因此非常適合無狀態的分散式系統。
  • 跨域支持:JWT 可以安全地在不同域間傳遞信息,適用於微服務架構和跨域應用。
  • 靈活性:可以在 Token 中攜帶用戶角色、權限等信息,便於細緻地授權控制。

JWT 的缺點

  • 無法撤銷:一旦 JWT 被簽發,除非設置過期時間,否則在到期前無法撤銷。如果 JWT 洩露,攻擊者可以在 Token 到期前使用它。
  • Token 大小問題:由於 JWT 是自包含的,攜帶的數據越多,Token 就會越大,這可能會影響頻繁網絡傳輸中的性能。

OAuth 2.0 與 JWT 的比較

雖然 OAuth 2.0 和 JWT 都能用來保護 API 和控制授權,但它們的使用場景和工作原理有所不同。

  • OAuth 2.0:是一個授權框架,適合與第三方應用整合,通過授權伺服器管理 Token 的發放與失效。OAuth 2.0 可以使用多種 Token 格式(如 JWT)。
  • JWT:是一種自包含的 Token 格式,適合用於內部系統或快速驗證身份的應用場景。JWT 可以與 OAuth 2.0 結合使用,也可以獨立應用。

每日小結

API 的安全性不容忽視。根據應用場景的不同,你可以選擇 API KeyOAuth 2.0JWT 來保護 API。OAuth 2.0 適合第三方應用整合,提供精細的授權控制,而 JWT 是一種高效的身份驗證技術,適合無狀態和分散式系統。今天我們介紹了三種 API 保護方式,明天將繼續探討如何將這些保護機制應用到實際的產品 API 中,確保其安全性。


上一篇
Day 16 常見API測試工具 Swagger與Postman
下一篇
Day 18: 保護你的 API(中)
系列文
使用 C# 從零開始玩轉 Web API,從基礎到微服務與雲端部署的全面探索22
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言