Postgres High的主要危险

时间:2017-01-05 01:55:31

标签: sql postgresql concurrency transactions

在Postgres High(PSD 9.6)中,书呆子和欢乐合唱俱乐部处于一场奇怪的共同战争中。书呆子策划了对欢乐俱乐部的秘密计划。欢乐合唱团以愉快的歌曲回应。

如果书呆子懦弱的话,欢乐合唱团永远不会回应。同样地,书呆子只是试图摆脱欢乐合唱团,所以如果欢乐合唱俱乐部没有回应,那么书呆子实际上并没有调用他们的秘密计划。

作为首席程序员,我的工作是确保只有一次可能的书呆子反叛尝试同时发生。我还必须确保两个书呆子都成功,欢乐俱乐部成功或者都没有成功。但那些 麻烦的书呆子,总是尝试sql注入攻击。也要防止这样做。正如Postgres High的所有优秀领导者所做的那样,我们用SQL编写课程计划。

课程计划:

begin;
-- stop race conditions with a hall monitor
select from semaphore where name = 'hall_monitor' for update;

prepare nerd_rebellion (
  text, -- secret_mission
  date -- when_we_strike
) as
  update ultimate_plan
    set secret_mission = $1
    where when_we_strike = $2;

prepare glee_club_counterstrike (
  text, -- happy_song
  boolean -- kill_them_with_love
) as
  insert into song_therapy (
    happy_song,
    kill_them_with_love
  ) values (
    $1,
    $2  
  )

execute nerd_rebellion(
  'Nerds do stuff like this ; drop table song_therapy --f you glee club',
  '2017-01-01'
);
execute glee_club_counterstrike(
  'god_bless_america',
  true
);
-- let us never speak of this again ...
deallocate nerd_rebellion
deallocate glee_club_counterstrike

-- all done. Release the hall monitor
commit;

天哪,这对校长来说很重要。我们的课程时间很短,我们准备和解除了所有这些。啊。真的切入我的咖啡和甜甜圈时间。但我需要在单个事务中包装多个语句并使用信号量进行序列化。不能在SQL注入上做出妥协。我没有看到更简单的解决方案。你呢?

1 个答案:

答案 0 :(得分:2)

你没有确定书呆子是否成功。书呆子可能会爆发(UPDATE可能没有排),欢乐合唱团无论如何都会唱歌。

您可以使用数据修改CTE或plpgsql函数链接这两个命令,您可以在其中使插入取决于更新是否成功。

这是校长可能使用的工具:

CREATE OR REPLACE FUNCTION nerd_strike(
      _secret_mission      text
    , _when_we_strike      date 
    , _happy_song          text
    , _kill_them_with_love boolean
   ) RETURNS void AS
$func$
BEGIN
   SELECT FROM semaphore WHERE name = 'hall_monitor' FOR UPDATE;

   UPDATE ultimate_plan
   SET    secret_mission = _secret_mission
   WHERE  when_we_strike = _when_we_strike;

   IF FOUND THEN  --  only if update actually succeeded
      INSERT INTO song_therapy (happy_song, kill_them_with_love)
      VALUES (_happy_song, _kill_them_with_love);
   END IF;
END
$func$  LANGUAGE plpgsql;

呼叫:

SELECT nerd_strike('Nerds do stuff like this ; drop table song_therapy --f you glee club'
                 , '2017-01-01'
                 , 'god_bless_america'
                 , true);

函数是原子的,所以一切都发生了或者从未发生过 参数作为 values 传递(非常类似于预处理语句),因此没有机会进行SQL注入。

相关: