2022-07-31 14:56:44 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-02-05 13:32:44 +01:00
|
|
|
RSpec.describe Rack::Protection do
|
2022-07-31 14:56:44 +02:00
|
|
|
it_behaves_like 'any rack application'
|
2011-10-04 15:06:43 -07:00
|
|
|
|
|
|
|
it 'passes on options' do
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, track: ['HTTP_FOO']
|
|
|
|
run proc { |_e| [200, { 'Content-Type' => 'text/plain' }, ['hi']] }
|
2011-10-04 15:06:43 -07:00
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
session = { foo: :bar }
|
2011-10-04 15:06:43 -07:00
|
|
|
get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'a'
|
|
|
|
get '/', {}, 'rack.session' => session, 'HTTP_ACCEPT_ENCODING' => 'b'
|
2014-09-03 01:54:36 +02:00
|
|
|
expect(session[:foo]).to eq(:bar)
|
2011-10-04 15:06:43 -07:00
|
|
|
|
|
|
|
get '/', {}, 'rack.session' => session, 'HTTP_FOO' => 'BAR'
|
2014-09-03 01:54:36 +02:00
|
|
|
expect(session).to be_empty
|
2011-10-04 15:06:43 -07:00
|
|
|
end
|
2012-12-10 13:54:27 -07:00
|
|
|
|
2013-03-10 19:09:27 +01:00
|
|
|
it 'passes errors through if :reaction => :report is used' do
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, reaction: :report
|
|
|
|
run proc { |e| [200, { 'Content-Type' => 'text/plain' }, [e['protection.failed'].to_s]] }
|
2013-03-10 19:09:27 +01:00
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
session = { foo: :bar }
|
2013-03-10 19:09:27 +01:00
|
|
|
post('/', {}, 'rack.session' => session, 'HTTP_ORIGIN' => 'http://malicious.com')
|
2014-09-03 01:54:36 +02:00
|
|
|
expect(last_response).to be_ok
|
2022-07-31 14:56:44 +02:00
|
|
|
expect(body).to eq('true')
|
2013-03-10 19:09:27 +01:00
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
describe '#react' do
|
2014-03-13 11:55:59 +04:00
|
|
|
it 'prevents attacks and warns about it' do
|
|
|
|
io = StringIO.new
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, logger: Logger.new(io)
|
2014-03-13 11:55:59 +04:00
|
|
|
run DummyApp
|
|
|
|
end
|
|
|
|
post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
|
2014-09-03 02:24:32 +02:00
|
|
|
expect(io.string).to match(/prevented.*Origin/)
|
2014-03-13 11:55:59 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'reports attacks if reaction is to report' do
|
|
|
|
io = StringIO.new
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, reaction: :report, logger: Logger.new(io)
|
2014-03-13 11:55:59 +04:00
|
|
|
run DummyApp
|
|
|
|
end
|
|
|
|
post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
|
2014-09-03 02:24:32 +02:00
|
|
|
expect(io.string).to match(/reported.*Origin/)
|
|
|
|
expect(io.string).not_to match(/prevented.*Origin/)
|
2014-03-13 11:55:59 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'passes errors to reaction method if specified' do
|
|
|
|
io = StringIO.new
|
|
|
|
Rack::Protection::Base.send(:define_method, :special) { |*args| io << args.inspect }
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, reaction: :special, logger: Logger.new(io)
|
2014-03-13 11:55:59 +04:00
|
|
|
run DummyApp
|
|
|
|
end
|
|
|
|
post('/', {}, 'rack.session' => {}, 'HTTP_ORIGIN' => 'http://malicious.com')
|
2014-09-03 02:24:32 +02:00
|
|
|
expect(io.string).to match(/HTTP_ORIGIN.*malicious.com/)
|
|
|
|
expect(io.string).not_to match(/reported|prevented/)
|
2014-03-13 11:55:59 +04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
describe '#html?' do
|
|
|
|
context 'given an appropriate content-type header' do
|
|
|
|
subject { Rack::Protection::Base.new(nil).html? 'content-type' => 'text/html' }
|
2014-09-03 01:54:36 +02:00
|
|
|
it { is_expected.to be_truthy }
|
2012-12-10 13:54:27 -07:00
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
context 'given an appropriate content-type header of text/xml' do
|
|
|
|
subject { Rack::Protection::Base.new(nil).html? 'content-type' => 'text/xml' }
|
2018-03-27 20:13:44 -07:00
|
|
|
it { is_expected.to be_truthy }
|
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
context 'given an appropriate content-type header of application/xml' do
|
|
|
|
subject { Rack::Protection::Base.new(nil).html? 'content-type' => 'application/xml' }
|
2018-03-27 20:13:44 -07:00
|
|
|
it { is_expected.to be_truthy }
|
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
context 'given an inappropriate content-type header' do
|
|
|
|
subject { Rack::Protection::Base.new(nil).html? 'content-type' => 'image/gif' }
|
2014-09-03 01:54:36 +02:00
|
|
|
it { is_expected.to be_falsey }
|
2012-12-10 13:54:27 -07:00
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
context 'given no content-type header' do
|
2012-12-10 13:54:27 -07:00
|
|
|
subject { Rack::Protection::Base.new(nil).html?({}) }
|
2014-09-03 01:54:36 +02:00
|
|
|
it { is_expected.to be_falsey }
|
2012-12-10 13:54:27 -07:00
|
|
|
end
|
|
|
|
end
|
2013-08-21 14:50:51 -04:00
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
describe '#instrument' do
|
2013-08-21 14:50:51 -04:00
|
|
|
let(:env) { { 'rack.protection.attack' => 'base' } }
|
|
|
|
let(:instrumenter) { double('Instrumenter') }
|
|
|
|
|
|
|
|
after do
|
|
|
|
app.instrument(env)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an instrumenter specified' do
|
2022-07-31 14:56:44 +02:00
|
|
|
let(:app) { Rack::Protection::Base.new(nil, instrumenter: instrumenter) }
|
2013-08-21 14:50:51 -04:00
|
|
|
|
2014-09-03 01:54:36 +02:00
|
|
|
it { expect(instrumenter).to receive(:instrument).with('rack.protection', env) }
|
2013-08-21 14:50:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'with no instrumenter specified' do
|
|
|
|
let(:app) { Rack::Protection::Base.new(nil) }
|
|
|
|
|
2014-09-03 01:54:36 +02:00
|
|
|
it { expect(instrumenter).not_to receive(:instrument) }
|
2013-08-21 14:50:51 -04:00
|
|
|
end
|
|
|
|
end
|
2016-07-26 17:37:38 +09:00
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
describe 'new' do
|
2016-07-26 17:37:38 +09:00
|
|
|
it 'should allow disable session protection' do
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, without_session: true
|
2016-07-26 17:37:38 +09:00
|
|
|
run DummyApp
|
|
|
|
end
|
|
|
|
|
2022-07-31 14:56:44 +02:00
|
|
|
session = { foo: :bar }
|
2016-07-26 17:37:38 +09:00
|
|
|
get '/', {}, 'rack.session' => session, 'HTTP_USER_AGENT' => 'a'
|
|
|
|
get '/', {}, 'rack.session' => session, 'HTTP_USER_AGENT' => 'b'
|
|
|
|
expect(session[:foo]).to eq :bar
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should allow disable CSRF protection' do
|
|
|
|
mock_app do
|
2022-07-31 14:56:44 +02:00
|
|
|
use Rack::Protection, without_session: true
|
2016-07-26 17:37:38 +09:00
|
|
|
run DummyApp
|
|
|
|
end
|
|
|
|
|
|
|
|
post('/', {}, 'HTTP_REFERER' => 'http://example.com/foo', 'HTTP_HOST' => 'example.org')
|
|
|
|
expect(last_response).to be_ok
|
|
|
|
end
|
|
|
|
end
|
2011-05-29 11:45:27 +02:00
|
|
|
end
|