Security Barrier Views (without waiting for 9.2)

While making my rounds through the Internet today I came across a great article by Robert Haas on the topic of Security Barrier Views. Robert pointed out that simply by using a quick boolean function, one can use it to leak data from views that are normally used for row-level security. As you can imagine, this is a fairly serious topic for the Schemaverse as being able to leak data on other players and their scripts, ships and events can certainly help you gain a serious advantage. 

You can take a look at Robert’s article for his own example of this but I will show what is happening in terms of The Schemaverse. 

First off a player logs in and creates a new function (this part is care of Robert)

CREATE OR REPLACE FUNCTION pg_temp.leak(text) returns bool as
raise notice ‘%’, $1; return true; 
end$$ language plpgsql cost 0.0000000000000001; 

This function will take whatever is passed to it and return it as a notice along with the query results.

A player using this function along with, say, the my_fleets view would run the following query:

select * from my_fleets where pg_temp.leak(script);

and they would receive:

NOTICE:<other players script>
NOTICE:<other players script>

NOTICE:<other players script> 

fleet_id | player_id | script | script_declarations
1 | 1 | <players own script> | <etc>

The view still works as expected, only listing the players own fleets but all the scripts have also been sent one-by-one. 

For reference, here is the my_fleets view definition:


 SELECT,, fleet.script, fleet.script_declarations, fleet.last_script_update_tic, fleet.enabled, fleet.runtime

   FROM fleet

  WHERE fleet.player_id = get_player_id(“session_user”());

Given that row-level security using views is how The Schemaverse works, seeing this work was pretty depressing but also yet another fun challenge to try and overcome. My initial thoughts where to remove the ability for players to create temporary functions. This is apparently not possible (please correct me if this is the case).

Then I had another idea though: Limit the results before the player’s where clauses is applied.

Keeping the fleet scripts secure tends to be my biggest priority as this is where all the players efforts go to. For that reason, I tried to tackle securing my_fleets against this attack first.

In PostgreSQL you can create functions that return result sets so first I created a new type that my function will reference named my_fleets_type.

create type my_fleets_type as
id integer,
name character varying,
script text,
script_declarations text, 
last_script_update integer,
enabled boolean,
runtime interval

 I then moved the my_fleeets view query into a function my_fleets_security():

CREATE OR REPLACE FUNCTION my_fleets_security() RETURNS setof my_fleets_type as $my_fleets_security$
r record;
FOR r IN SELECT,, fleet.script, fleet.script_declarations, fleet.last_script_update_tic, fleet.enabled,fleet.runtime
FROM fleet
WHERE fleet.player_id = get_player_id(“session_user”())
RETURN next r;
$my_fleets_security$ language ‘plpgsql’ SECURITY DEFINER; 

Finally, to finish everything up, I changed the my_fleets view to call the function rather then the query:

CREATE OR REPLACE VIEW my_fleets AS SELECT * FROM my_fleets_security();

Done and done. If you try the same trick on this, you only get your own scripts noticed back since the player’s view where-clause is being performed on the result set returned by the function. 

This change is fairly time consuming to pull off so this round is fair game for playing around with the bug. Your fleet scripts are safe (for now) but some spies may know you are coming during your big attack. 

Also, potentially welcome to The Schemaverse’s dev blog. I know there is a lot of places to discuss this game already but I wanted one central point where I can make announcements that are larger than 140 characters like this one. Please keep using the group and github for discussion though.