Khóa chặt API của bạn: Các biện pháp bảo mật đơn giản (Whitelisting, JSON Web Tokens, API Keys, OAuth 2.0, Basic Authentication, Hash-based Message Authentication Code)

API không bảo mật là những điểm yếu. Học cách bảo mật API REST của bạn một cách hiệu quả: Whitelisting, JSON Web Tokens, API Keys, OAuth 2.0, Basic Authentication, Hash-based Message Authentication Code để xác thực an toàn.
Khóa chặt API của bạn: Các biện pháp bảo mật đơn giản (Whitelisting, JSON Web Tokens, API Keys, OAuth 2.0, Basic Authentication, Hash-based Message Authentication Code)

REST APIs https://vulehuan.com/vi/blog/2024/7/rest-apis-giao-tiep-don-gian-cho-cac-ung-dung-manh-me-668a1816f0915ca45912b90d.html giống như những cánh cửa vào ứng dụng web của bạn. Cũng như bạn khóa cửa nhà của mình, bạn cần bảo mật API. Dưới đây là hai cách đơn giản để làm điều đó: Whitelisting các trang web và sử dụng Tokens.

Whitelisting các trang web

Hãy tưởng tượng bạn có một bữa tiệc, và bạn chỉ muốn bạn bè của mình đến. Bạn lập danh sách tên của họ và kiểm tra tại cửa. Whitelisting hoạt động theo cách tương tự cho API:

  • Lập danh sách các trang web được phép
  • Khi có yêu cầu, kiểm tra xem nó có từ trang web được phép hay không
  • Nếu có, cho phép nó thông qua. Nếu không, chặn lại
require 'sinatra'

ALLOWED_DOMAINS = ['client-1.com', 'client-2.net']

get '/api/orders' do
  origin = request.env['HTTP_ORIGIN']
  unless ALLOWED_DOMAINS.any? { |domain| origin&.include?(domain) }
    halt 403, "Access denied"
  end
  # Your code
end

request.env['HTTP_ORIGIN'] không hoàn toàn an toàn một mình nó:

  • HTTP_ORIGIN là gì? HTTP_ORIGIN dựa trên tiêu đề Origin được gửi bởi client. Tiêu đề này nhằm chỉ ra nơi yêu cầu bắt nguồn từ.
  • Nó có thể bị giả mạo không? Có, nó có thể bị giả mạo. Bất kỳ tiêu đề HTTP nào, bao gồm Origin, đều có thể bị client thao túng. Một người dùng ác ý có thể đặt bất kỳ giá trị nào họ muốn cho header này.
  • Tại sao nó vẫn được sử dụng? Mặc dù có những hạn chế, Origin vẫn hữu ích khi kết hợp với các biện pháp bảo mật khác, đặc biệt là cho các chính sách CORS (Cross-Origin Resource Sharing).

Làm thế nào để cải thiện bảo mật:

  • Không chỉ dựa vào Origin để đưa ra các quyết định bảo mật quan trọng.
  • Sử dụng nó kết hợp với các biện pháp bảo mật khác như xác thực JWT.
  • Triển khai các chính sách CORS đúng cách trên server của bạn.
  • Sử dụng HTTPS để ngăn chặn các cuộc tấn công man-in-the-middle có thể sửa đổi các header.

Sử dụng Tokens

Tokens giống như mật khẩu bí mật cho API của bạn. Đây là cách chúng hoạt động:

  • Khi người dùng đăng nhập, cung cấp cho họ một token đặc biệt
  • Người dùng gửi token này với mỗi yêu cầu API
  • API của bạn kiểm tra nếu token hợp lệ trước khi phản hồi

JSON Web Tokens (JWTs)

JWTs là một loại token phổ biến. Chúng giống như thẻ ID kỹ thuật số chứa:

  • Người dùng là ai
  • Khi nào token hết hạn
  • Chữ ký bí mật để chứng minh nó là thật

Cách sử dụng JWTs:

  • Người dùng đăng nhập bằng tên đăng nhập và mật khẩu
  • Máy chủ của bạn tạo một JWT và gửi lại
  • Ứng dụng của người dùng lưu trữ JWT
  • Đối với mỗi yêu cầu API, ứng dụng gửi JWT
  • API của bạn kiểm tra JWT trước khi phản hồi

Bằng cách kết hợp Whitelisting và JWTs https://github.com/jwt/ruby-jwt, bạn tạo ra hai lớp bảo mật. Nó giống như có một người gác cửa (Whitelisting) và kiểm tra thẻ ID bên trong (JWTs).
Ví dụ về một phương pháp mạnh mẽ hơn trong Ruby:

require 'sinatra'
require 'jwt'

SECRET_KEY = 'my_secret_key'
ALLOWED_DOMAINS = ['client-1.com', 'client-2.net']

before do
  # Check Origin as a first line of defense
  origin = request.env['HTTP_ORIGIN']
  unless ALLOWED_DOMAINS.any? { |domain| origin&.include?(domain) }
    halt 403, "Access denied"
  end

  # Verify JWT for more robust security
  token = request.env['HTTP_AUTHORIZATION']
  begin
    @payload = JWT.decode(token, SECRET_KEY, true, algorithm: 'HS256')[0]
  rescue JWT::DecodeError
    halt 401, "Invalid token"
  end
end

get '/api/orders' do
  # At this point, we've verified both Origin and JWT
  # Your code with @payload['username']
end

Các phương pháp khác

API Keys

Đơn giản để triển khai, nhưng ít an toàn hơn cho các hoạt động cụ thể của người dùng.
Ví dụ trong Ruby:

require 'sinatra'

API_KEYS = ['key1', 'key2', 'key3']

before do
  api_key = request.env['HTTP_X_API_KEY']
  halt 401, 'Invalid API Key' unless API_KEYS.include?(api_key)
end

get '/api/data' do
  "Here's your data!"
end

OAuth 2.0

Phức tạp hơn nhưng rất an toàn và được sử dụng rộng rãi cho xác thực bên thứ ba.
Ví dụ sử dụng gem oauth2:

require 'sinatra'
require 'oauth2'

client = OAuth2::Client.new('client_id', 'client_secret', site: 'https://example.com')

get '/auth' do
  redirect client.auth_code.authorize_url(redirect_uri: 'http://localhost:4567/callback')
end

get '/callback' do
  token = client.auth_code.get_token(params[:code], redirect_uri: 'http://localhost:4567/callback')
  session[:access_token] = token.token
  "You're authenticated!"
end

Basic Authentication

Ví dụ:

require 'sinatra'

use Rack::Auth::Basic, "Restricted Area" do |username, password|
  username == 'admin' && password == 'secret'
end

get '/api/data' do
  "Here's your protected data!"
end

HMAC (Mã xác thực thông điệp dựa trên hàm băm - Hash-based Message Authentication Code)

Tương tự như API keys nhưng an toàn hơn.
Ví dụ:

require 'sinatra'
require 'openssl'

SECRET_KEY = 'your_secret_key'

def valid_signature?(data, signature)
  calculated = OpenSSL::HMAC.hexdigest('SHA256', SECRET_KEY, data)
  calculated == signature
end

post '/api/data' do
  data = request.body.read
  signature = request.env['HTTP_X_SIGNATURE']
  
  halt 401

, 'Invalid signature' unless valid_signature?(data, signature)
  
  "Data received and verified!"
end

Mỗi phương pháp này đều có ưu và nhược điểm riêng:

  • API Keys đơn giản nhưng không cung cấp xác thực cụ thể cho người dùng.
  • OAuth 2.0 rất an toàn và linh hoạt nhưng phức tạp hơn để triển khai.
  • Basic Auth đơn giản nhưng gửi thông tin đăng nhập với mỗi yêu cầu.
  • HMAC cung cấp sự cân bằng tốt giữa bảo mật và đơn giản nhưng đòi hỏi triển khai cẩn thận.

Sự lựa chọn phụ thuộc vào nhu cầu cụ thể của bạn, chẳng hạn như loại ứng dụng, yêu cầu bảo mật và độ dễ dàng triển khai. Đối với nhiều API, sự kết hợp của các phương pháp này có thể cung cấp bảo mật mạnh mẽ.