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.
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:
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ừ.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.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:
Origin
để đưa ra các quyết định bảo mật quan trọng.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:
JWTs là một loại token phổ biến. Chúng giống như thẻ ID kỹ thuật số chứa:
Cách sử dụng JWTs:
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
Đơ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
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
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
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:
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ẽ.