Browse Source

DOS protection

pull/1/head
Nicolae Claudius 13 years ago
parent
commit
47e2137595
  1. 12
      app/models/domain.rb
  2. 7
      app/models/record.rb
  3. 3
      config/settings.sample.yml
  4. 2
      spec/factories.rb
  5. 15
      spec/models/domain_spec.rb
  6. 16
      spec/models/record_spec.rb

12
app/models/domain.rb

@ -34,7 +34,9 @@ class Domain < ActiveRecord::Base
:minimum => 2, :maximum => 10, :message => "must have be at least 2, at most 10"} :minimum => 2, :maximum => 10, :message => "must have be at least 2, at most 10"}
validates_associated :records validates_associated :records
validates :user_id, :presence => true validates :user_id, :presence => true
validate do # domain ownership
validate :domain_ownership
def domain_ownership # domain ownership
segments = name.split('.') segments = name.split('.')
if segments.size > 2 if segments.size > 2
parent = segments[1..-1].join('.') parent = segments[1..-1].join('.')
@ -44,6 +46,14 @@ class Domain < ActiveRecord::Base
end end
end end
validate :max_domains_per_user, :on => :create
def max_domains_per_user # domains per user limit for DOS protection
max = Settings.max_domains_per_user.to_i
if user.domains.count >= max
errors.add :base, "as a security measure, you cannot have more than #{max} domains on one account"
end
end
def slave?; self.type == 'SLAVE' end def slave?; self.type == 'SLAVE' end
before_create do before_create do

7
app/models/record.rb

@ -16,6 +16,13 @@ class Record < ActiveRecord::Base
:only_integer => true :only_integer => true
}, :allow_blank => true }, :allow_blank => true
validates :authentication_token, :presence => true, :uniqueness => true validates :authentication_token, :presence => true, :uniqueness => true
validate :max_records_per_domain, :on => :create
def max_records_per_domain # domains per user limit for DOS protection
max = Settings.max_records_per_domain.to_i
if domain.records.count >= max
errors.add :base, "as a security measure, you cannot have more than #{max} records on one domain"
end
end
before_validation :generate_token, :on => :create before_validation :generate_token, :on => :create
before_validation :prepare_name! before_validation :prepare_name!

3
config/settings.sample.yml

@ -1,4 +1,3 @@
default_ttl: 3600 default_ttl: 3600
min_ttl: 60 min_ttl: 60
ns: ns:
@ -17,3 +16,5 @@ protected_hostnames:
- ns[0-9]* - ns[0-9]*
support_mail: "support@entrydns.net" support_mail: "support@entrydns.net"
honeypot: userid honeypot: userid
max_domains_per_user: 200
max_records_per_domain: 500

2
spec/factories.rb

@ -5,6 +5,8 @@ FactoryGirl.define do
sequence(:domain_name){|n| "#{n}#{Faker::Internet.domain_name}"} sequence(:domain_name){|n| "#{n}#{Faker::Internet.domain_name}"}
factory :user do factory :user do
first_name {Faker::Name.first_name}
last_name {Faker::Name.last_name}
email email
password password
password_confirmation {password} password_confirmation {password}

15
spec/models/domain_spec.rb

@ -31,4 +31,19 @@ describe Domain do
end end
(domain.soa_record.serial % 10).should == 0 (domain.soa_record.serial % 10).should == 0
end end
it "protects DOS on more Settings.max_domains_per_user+ domains" do
max = Settings.max_domains_per_user.to_i
domain.stub_chain(:user, :domains, :count).and_return(max)
domain.max_domains_per_user
domain.should have(1).errors
end
it "is DOS-valid on less than Settings.max_domains_per_user domains" do
max = Settings.max_domains_per_user.to_i
domain.stub_chain(:user, :domains, :count).and_return(max-1)
domain.max_domains_per_user
domain.should be_valid
end
end end

16
spec/models/record_spec.rb

@ -1,5 +1,19 @@
require 'spec_helper' require 'spec_helper'
describe Record do describe Record do
pending "add some examples to (or delete) #{__FILE__}" include_context "data"
it "protects DOS on more Settings.max_records_per_domain+ domains" do
max = Settings.max_records_per_domain.to_i
a_record.domain.stub_chain(:records, :count).and_return(max)
a_record.max_records_per_domain
a_record.should have(1).errors
end
it "is DOS-valid on less than Settings.max_records_per_domain domains" do
max = Settings.max_records_per_domain.to_i
a_record.domain.stub_chain(:records, :count).and_return(max)
a_record.max_records_per_domain
a_record.should be_valid
end
end end

Loading…
Cancel
Save