[deploy] Track and Limit API writes by IP Address (#7847)
This commit is contained in:
parent
2497d53929
commit
8ae486a362
2 changed files with 32 additions and 24 deletions
|
|
@ -2,37 +2,45 @@ Rack::Attack.throttled_response_retry_after_header = true
|
|||
|
||||
class Rack::Attack
|
||||
throttle("search_throttle", limit: 5, period: 1) do |request|
|
||||
if request.path.starts_with?("/search/") && request.env["HTTP_FASTLY_CLIENT_IP"].present?
|
||||
Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
request.env["HTTP_FASTLY_CLIENT_IP"].to_s
|
||||
return if request.env["HTTP_FASTLY_CLIENT_IP"].blank?
|
||||
|
||||
if request.path.starts_with?("/search/")
|
||||
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
end
|
||||
end
|
||||
|
||||
throttle("api_throttle", limit: 3, period: 1) do |request|
|
||||
if request.path.starts_with?("/api/") && request.get? && request.env["HTTP_FASTLY_CLIENT_IP"].present?
|
||||
Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
request.env["HTTP_FASTLY_CLIENT_IP"].to_s
|
||||
return if request.env["HTTP_FASTLY_CLIENT_IP"].blank?
|
||||
|
||||
if request.path.starts_with?("/api/") && request.get?
|
||||
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
end
|
||||
end
|
||||
|
||||
throttle("api_write_throttle", limit: 1, period: 1) do |request|
|
||||
return if request.env["HTTP_FASTLY_CLIENT_IP"].blank?
|
||||
|
||||
if request.path.starts_with?("/api/") && (request.put? || request.post? || request.delete?)
|
||||
Honeycomb.add_field("user_api_key", request.env["HTTP_API_KEY"])
|
||||
request.env["HTTP_API_KEY"]
|
||||
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
end
|
||||
end
|
||||
|
||||
throttle("site_hits", limit: 40, period: 2) do |request|
|
||||
if request.env["HTTP_FASTLY_CLIENT_IP"].present?
|
||||
Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
request.env["HTTP_FASTLY_CLIENT_IP"].to_s
|
||||
end
|
||||
return if request.env["HTTP_FASTLY_CLIENT_IP"].blank?
|
||||
|
||||
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
end
|
||||
|
||||
throttle("message_throttle", limit: 2, period: 1) do |request|
|
||||
if request.path.starts_with?("/messages") && request.post? && request.env["HTTP_FASTLY_CLIENT_IP"].present?
|
||||
Honeycomb.add_field("fastly_client_ip", request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
request.env["HTTP_FASTLY_CLIENT_IP"].to_s
|
||||
return if request.env["HTTP_FASTLY_CLIENT_IP"].blank?
|
||||
|
||||
if request.path.starts_with?("/messages") && request.post?
|
||||
track_and_return_ip(request.env["HTTP_FASTLY_CLIENT_IP"])
|
||||
end
|
||||
end
|
||||
|
||||
def self.track_and_return_ip(ip_address)
|
||||
Honeycomb.add_field("fastly_client_ip", ip_address)
|
||||
ip_address.to_s
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -49,21 +49,21 @@ describe Rack::Attack, type: :request, throttle: true do
|
|||
let(:api_secret) { create(:api_secret) }
|
||||
let(:another_api_secret) { create(:api_secret) }
|
||||
|
||||
it "throttles api write endpoints based on api-key" do
|
||||
headers = { "api-key" => api_secret.secret, "content-type" => "application/json" }
|
||||
dif_headers = { "api-key" => another_api_secret.secret, "content-type" => "application/json" }
|
||||
params = { body_markdown: "", title: Faker::Book.title }
|
||||
it "throttles api write endpoints based on IP" do
|
||||
headers = { "api-key" => api_secret.secret, "content-type" => "application/json", "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
|
||||
dif_headers = { "api-key" => another_api_secret.secret, "content-type" => "application/json", "HTTP_FASTLY_CLIENT_IP" => "1.1.1.1" }
|
||||
params = { article: { body_markdown: "", title: Faker::Book.title } }.to_json
|
||||
|
||||
Timecop.freeze do
|
||||
valid_response = post api_articles_path, params: { article: params }.to_json, headers: headers
|
||||
throttled_response = post api_articles_path, params: { article: params }.to_json, headers: headers
|
||||
new_api_response = post api_articles_path, params: { article: params }.to_json, headers: dif_headers
|
||||
valid_response = post api_articles_path, params: params, headers: headers
|
||||
throttled_response = post api_articles_path, params: params, headers: headers
|
||||
new_api_response = post api_articles_path, params: params, headers: dif_headers
|
||||
|
||||
expect(valid_response).not_to eq(429)
|
||||
expect(throttled_response).to eq(429)
|
||||
expect(new_api_response).not_to eq(429)
|
||||
expect(Honeycomb).to have_received(:add_field).with("user_api_key", api_secret.secret).exactly(2).times
|
||||
expect(Honeycomb).to have_received(:add_field).with("user_api_key", another_api_secret.secret)
|
||||
expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "5.6.7.8").exactly(3).times
|
||||
expect(Honeycomb).to have_received(:add_field).with("fastly_client_ip", "1.1.1.1").exactly(2).times
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue