隨著 API 在現代應用程式中的使用日益普及,API 安全性成為開發者不可忽視的重要課題。當你開發一個公開的 API 時,確保其安全性是至關重要的。今天,我們將深入探討 API 的幾種常見保護方式,包括 API Key、OAuth 2.0、以及 JWT(JSON Web Token),並介紹如何使用這些方法來防止未授權的訪問與攻擊。
API 是應用程式與外部系統的交互接口,經常處理著敏感數據和關鍵業務邏輯。未妥善保護的 API 可能面臨數據洩露、未授權訪問、DDoS 攻擊等風險。因此,保護 API 是確保系統穩定性、數據安全和用戶隱私的必要措施。
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("成功獲取保護的資源!");
}
}
優點:
缺點:
OAuth 2.0 是一個更為強大且安全的授權框架,特別適用於需要與第三方應用整合的場景。它允許應用程式在不需要用戶密碼的情況下,安全地訪問用戶的受保護資源。
OAuth 2.0 主要使用「授權碼流程」(Authorization Code Flow),流程如下:
範例程式碼展示 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);
}
JWT 是一種廣泛使用的身份驗證技術,它將身份驗證和授權信息打包成一個自包含的 Token。JWT 是由三部分組成的:Header、Payload 和 Signature,這些部分經過編碼後生成 Token,並可以攜帶用戶的身份信息,這使得系統在多次請求中不必每次查詢數據庫即可驗證身份。
用戶登入並獲取 JWT:當用戶成功登入後,伺服器生成一個 JWT,並將其發送給用戶。
使用 JWT 發送請求:用戶將該 JWT 附加到後續 API 請求的 Authorization Header 中,形式如下:
Authorization: Bearer <JWT>
伺服器驗證 JWT:伺服器解析並驗證 JWT,確認其合法性。如果 JWT 有效,請求將被授權繼續,否則返回未授權的錯誤。
Header:指定 Token 的類型(typ)和使用的簽名算法(alg)。
{
"alg": "HS256",
"typ": "JWT"
}
Payload:包含聲明(claims),例如用戶 ID、角色或其他信息。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
Signature:使用密鑰來對 Header 和 Payload 進行簽名,保證 Token 的完整性。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
下面展示了如何在 .NET Core 中使用 JWT 來保護 API。
在 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();
});
}
使用 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);
}
}
Authorize
屬性來保護 API有了 JWT 驗證配置後,我們可以使用 [Authorize]
屬性來保護 API 路由,確保只有攜帶有效 JWT Token 的請求才能訪問受保護的資源。
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class JwtController : ControllerBase
{
[HttpGet]
public IActionResult GetProtectedData()
{
return Ok("你已成功通過 JWT 驗證,獲取到保護的數據!");
}
}
雖然 OAuth 2.0 和 JWT 都能用來保護 API 和控制授權,但它們的使用場景和工作原理有所不同。
API 的安全性不容忽視。根據應用場景的不同,你可以選擇 API Key、OAuth 2.0 或 JWT 來保護 API。OAuth 2.0 適合第三方應用整合,提供精細的授權控制,而 JWT 是一種高效的身份驗證技術,適合無狀態和分散式系統。今天我們介紹了三種 API 保護方式,明天將繼續探討如何將這些保護機制應用到實際的產品 API 中,確保其安全性。