This is a fix for public messages, where a malicious pod could spoof a message from someone a user was connected to, as the verified signatures were not checked that the object was also from said sender. This hole only affected public messages, and the private part of code had the correct checks THX to s-f-s(Stephan Schulz) for reporting and tracking down this issue, and props to Raven24(florian.staudacher@gmx.at) for helping me test the patch
262 lines
8.8 KiB
Ruby
262 lines
8.8 KiB
Ruby
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
|
# licensed under the Affero General Public License version 3 or later. See
|
|
# the COPYRIGHT file.
|
|
|
|
require 'spec_helper'
|
|
|
|
|
|
def receive(post, opts)
|
|
sender = opts.fetch(:from)
|
|
receiver = opts.fetch(:by)
|
|
salmon_xml = sender.salmon(post).xml_for(receiver.person)
|
|
zord = Postzord::Receiver::Private.new(receiver, :salmon_xml => salmon_xml)
|
|
zord.perform!
|
|
end
|
|
|
|
def receive_public(post, opts)
|
|
sender = opts.fetch(:from)
|
|
salmon_xml = Salmon::Slap.create_by_user_and_activity(sender, post.to_diaspora_xml).xml_for(nil)
|
|
post.destroy
|
|
zord = Postzord::Receiver::Public.new(salmon_xml)
|
|
zord.perform!
|
|
end
|
|
|
|
def temporary_user(&block)
|
|
user = Factory(:user)
|
|
block_return_value = yield user
|
|
user.delete
|
|
block_return_value
|
|
end
|
|
|
|
def temporary_post(user, &block)
|
|
temp_post = user.post(:status_message, :text => 'hi')
|
|
block_return_value = yield temp_post
|
|
temp_post.delete
|
|
block_return_value
|
|
end
|
|
|
|
def expect_error(partial_message, &block)# DOES NOT REQUIRE ERROR!!
|
|
begin
|
|
yield
|
|
rescue => e
|
|
e.message.should match partial_message
|
|
|
|
ensure
|
|
raise "no error occured where expected" unless e.present?
|
|
end
|
|
end
|
|
|
|
def bogus_retraction(&block)
|
|
ret = Retraction.new
|
|
yield ret
|
|
ret
|
|
end
|
|
|
|
def user_should_not_see_guid(user, guid)
|
|
user.reload.visible_shareables(Post).where(:guid => guid).should be_blank
|
|
end
|
|
#returns the message
|
|
def legit_post_from_user1_to_user2(user1, user2)
|
|
original_message = user1.post(:status_message, :text => 'store this!', :to => user1.aspects.find_by_name("generic").id)
|
|
receive(original_message, :from => user1, :by => user2)
|
|
original_message
|
|
end
|
|
|
|
describe "attack vectors" do
|
|
|
|
let(:eves_aspect) { eve.aspects.find_by_name("generic") }
|
|
let(:alices_aspect) { alice.aspects.find_by_name("generic") }
|
|
|
|
context "testing side effects of validation phase" do
|
|
|
|
describe 'Contact Required Unless Request' do
|
|
#CUSTOM SETUP; cant use helpers here
|
|
it 'does not save a post from a non-contact as a side effect' do
|
|
salmon_xml = nil
|
|
bad_post_guid = nil
|
|
|
|
temporary_user do |bad_user|
|
|
temporary_post(bad_user) do |post_from_non_contact|
|
|
bad_post_guid = post_from_non_contact.guid
|
|
salmon_xml = bad_user.salmon(post_from_non_contact).xml_for(bob.person)
|
|
end
|
|
end
|
|
|
|
zord = Postzord::Receiver::Private.new(bob, :salmon_xml => salmon_xml)
|
|
|
|
expect {
|
|
expect_error /Contact required/ do
|
|
zord.perform!
|
|
end
|
|
}.should_not change(Post, :count)
|
|
|
|
user_should_not_see_guid(bob, bad_post_guid)
|
|
end
|
|
|
|
|
|
#CUSTOM SETUP; cant use helpers here
|
|
it 'other users can not grant visiblity to another users posts by sending their friends post to themselves (even if they are contacts)' do
|
|
#setup: eve has a message. then, alice is connected to eve.
|
|
#(meaning alice can not see the old post, but it exists in the DB)
|
|
# bob takes eves message, changes the post author to himself
|
|
# bob trys to send a message to alice
|
|
original_message = eve.post(:status_message, :text => 'store this!', :to => eves_aspect.id)
|
|
original_message.diaspora_handle = bob.diaspora_handle
|
|
|
|
alice.contacts.create(:person => eve.person, :aspects => [alice.aspects.first])
|
|
|
|
salmon_xml = bob.salmon(original_message).xml_for(alice.person)
|
|
|
|
#bob sends it to himself?????
|
|
zord = Postzord::Receiver::Private.new(bob, :salmon_xml => salmon_xml)
|
|
|
|
expect_error /Contact required/ do
|
|
zord.perform!
|
|
end
|
|
|
|
#alice still should not see eves original post, even though bob sent it to her
|
|
user_should_not_see_guid(alice, original_message.guid)
|
|
end
|
|
end
|
|
|
|
describe 'author does not match xml author' do
|
|
it 'should not overwrite another persons profile profile' do
|
|
profile = eve.profile.clone
|
|
profile.first_name = "Not BOB"
|
|
|
|
expect {
|
|
expect_error /Author does not match XML author/ do
|
|
receive(profile, :from => alice, :by => bob)
|
|
end
|
|
}.should_not change(eve.profile, :first_name)
|
|
end
|
|
end
|
|
|
|
|
|
it 'public stuff should not be spoofed from another author' do
|
|
post = Factory(:status_message, :public => true, :author => eve.person)
|
|
expect_error /Author does not match XML author/ do
|
|
receive_public(post, :from => alice)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
context 'malicious contact attack vector' do
|
|
describe 'mass assignment on id' do
|
|
it "does not save a message over an old message with a different author" do
|
|
#setup: A user has a message with a given guid and author
|
|
original_message = legit_post_from_user1_to_user2(eve, bob)
|
|
|
|
#someone else tries to make a message with the same guid
|
|
malicious_message = Factory.build(:status_message, :id => original_message.id, :guid => original_message.guid, :author => alice.person)
|
|
|
|
expect{
|
|
receive(malicious_message, :from => alice, :by => bob)
|
|
}.should_not change(original_message, :author_id)
|
|
end
|
|
|
|
it 'does not save a message over an old message with the same author' do
|
|
#setup:
|
|
# i have a legit message from eve
|
|
original_message = legit_post_from_user1_to_user2(eve, bob)
|
|
|
|
#eve tries to send me another message with the same ID
|
|
malicious_message = Factory.build( :status_message, :id => original_message.id, :text => 'BAD!!!', :author => eve.person)
|
|
|
|
expect {
|
|
receive(malicious_message, :from => eve, :by => bob)
|
|
}.should_not change(original_message, :text)
|
|
end
|
|
end
|
|
|
|
|
|
it "ignores retractions on a post not owned by the retraction's sender" do
|
|
original_message = legit_post_from_user1_to_user2(eve, bob)
|
|
|
|
ret = bogus_retraction do |retraction|
|
|
retraction.post_guid = original_message.guid
|
|
retraction.diaspora_handle = alice.person.diaspora_handle
|
|
retraction.type = original_message.class.to_s
|
|
end
|
|
|
|
expect {
|
|
receive(ret, :from => alice, :by => bob)
|
|
}.should_not change(StatusMessage, :count)
|
|
end
|
|
|
|
it "silently disregards retractions for non-existent posts(that are from someone other than the post's author)" do
|
|
bogus_retraction = temporary_post(eve) do |original_message|
|
|
bogus_retraction do |ret|
|
|
ret.post_guid = original_message.guid
|
|
ret.diaspora_handle = alice.person.diaspora_handle
|
|
ret.type = original_message.class.to_s
|
|
end
|
|
end
|
|
expect{
|
|
receive(bogus_retraction, :from => alice, :by => bob)
|
|
}.should_not raise_error
|
|
end
|
|
|
|
it 'should not receive retractions where the retractor and the salmon author do not match' do
|
|
original_message = legit_post_from_user1_to_user2(eve, bob)
|
|
|
|
retraction = bogus_retraction do |ret|
|
|
ret.post_guid = original_message.guid
|
|
ret.diaspora_handle = eve.person.diaspora_handle
|
|
ret.type = original_message.class.to_s
|
|
end
|
|
|
|
expect {
|
|
expect_error /Author does not match XML author/ do
|
|
receive(retraction, :from => alice, :by => bob)
|
|
end
|
|
}.should_not change(bob.visible_shareables(Post), :count)
|
|
|
|
end
|
|
|
|
it 'it should not allow you to send retractions for other people' do
|
|
#we are banking on bob being friends with alice and eve
|
|
#here, alice is trying to disconnect bob and eve
|
|
|
|
retraction = bogus_retraction do |ret|
|
|
ret.post_guid = eve.person.guid
|
|
ret.diaspora_handle = alice.person.diaspora_handle
|
|
ret.type = eve.person.class.to_s
|
|
end
|
|
|
|
expect{
|
|
receive(retraction, :from => alice, :by => bob)
|
|
}.should_not change{bob.reload.contacts.count}
|
|
end
|
|
|
|
it 'it should not allow you to send retractions with xml and salmon handle mismatch' do
|
|
retraction = bogus_retraction do |ret|
|
|
ret.post_guid = eve.person.guid
|
|
ret.diaspora_handle = eve.person.diaspora_handle
|
|
ret.type = eve.person.class.to_s
|
|
end
|
|
|
|
expect{
|
|
expect_error /Author does not match XML author/ do
|
|
receive(retraction, :from => alice, :by => bob)
|
|
end
|
|
}.should_not change(bob.contacts, :count)
|
|
end
|
|
|
|
it 'does not let another user update other persons post' do
|
|
original_message = eve.post(:photo, :user_file => uploaded_photo, :text => "store this!", :to => eves_aspect.id)
|
|
receive(original_message, :from => eve, :by => bob)
|
|
|
|
#is this testing two things?
|
|
new_message = original_message.dup
|
|
new_message.diaspora_handle = alice.diaspora_handle
|
|
new_message.text = "bad bad bad"
|
|
|
|
expect{
|
|
receive(new_message, :from => alice, :by => bob)
|
|
}.should_not change(original_message, :text)
|
|
end
|
|
end
|
|
end
|