受限制的Web应用程序的PostgreSQL权限

时间:2017-01-08 20:57:23

标签: database postgresql web-applications privileges least-privilege

目标

创建一个包含三个用户的数据库并限制他们的权限(我只是大声思考,所以我的用户分离也可以纠正):

  1. 超级用户 - 此用户允许最初的数据库配置。创建应用程序数据库,创建其他用户,设置其权限。默认postgres超级用户适合我,所以这一个已经完成。
  2. 管理员 - 此用户只能访问在配置期间创建的数据库。管理员可以CRUD所有表中的所有数据,也可以是CRUD表等。"仅用于此数据库的超级用户"情况类型。在更新应用程序时,管理员是自动化工具用于处理数据库迁移的用户。
  3. 应用程序用户 - 此用户最终是支持Web应用程序功能的用户。请注意,这与网页上的用户无关 - 这是服务器用来运行查询,插入和删除数据的用户。我明确希望此用户能够修改任何内容的权限,也不能创建/销毁表或索引或任何结构。
  4. 我尝试了什么

    首先,看一下(通常很棒的)PostgreSQL文档,page on Grant几乎让我眼花缭乱。花了几个小时阅读有关PostgreSQL角色和特权的消息后,我常常感到困惑。我认为通过更多的工作,我能够确定我对管理员用户的要求,但我很难坚持使用#34; app用户"。我已经掌握了这一点(命名和密码都只是占位符):

    $ psql -U postgres
    postgres=# CREATE USER "app-admin" WITH PASSWORD 'password';
    CREATE ROLE
    postgres=# CREATE USER "app-user" WITH PASSWORD 'password';
    CREATE ROLE
    postgres=# CREATE DATABASE "test-database" WITH OWNER "app-admin";
    CREATE DATABASE
    postgres=# \c "test-database"
    You are now connected to database "test-database" as user "postgres".
    test-database=# DROP SCHEMA "public";
    DROP SCHEMA
    test-database=# CREATE SCHEMA "app" AUTHORIZATION "app-admin";
    CREATE SCHEMA
    

    这是我不确定的地方。我觉得我试图避免的答案是"默认情况下撤销所有内容,然后列举你在所有不同对象的所有不同级别上需要的所有权限"。我试图避免这种情况,因为我直接不知道我在那里需要什么。如果这最终成为答案,那么我只需要蹲下来阅读更多,但通常当我开始沿着这样的道路走下去时,我已经错过了一些东西。

    问题

    如何限制app-user的权限,以便他们无法修改任何结构数据(例如,无法添加或销毁表),但能够连接并对行执行任何操作(行级安全性甚至不在我的行上)雷达)。这种特权的一般模型是否与PostgreSQL预期的不同步?我觉得如果我不得不通过其中的每一个选项,我都会错过一些东西" grant"完成这样的事情的页面 - 无论是我最初做这件事的动机,还是我做这件事的方式。

    上下文

    我正在尝试构建我的第一个端到端Web应用程序。我已经做了足够的通用软件开发和Web应用程序开发,现在我正在努力理解我通常每天都认为理所当然的部分。我正在尝试设置PostgreSQL服务器,同时牢记principle of least privilege

    侧面追求

    我还没有在网络应用程序上看到这种情况,我只是加入了开发团队,尽管他们通常很小并且没有大量使用。这样做真的能做到吗?有没有人有令人信服的理由说明为什么要做这样的事情,或者为什么这是一个坏的或无效的想法?我的假设是,如果我最终得到一个SQL注入漏洞,这将减轻损害,因为数据库用户将具有有限的访问权限。这是误入歧途吗?

    我在这个问题上找到了很好的文章:

2 个答案:

答案 0 :(得分:8)

我首先回答你的“求职”问题:

对于您的担忧和担忧,您完全正确,并且设计应用程序的每个人都应该考虑相同的事情。其他一切都是草率和粗心。

为了减轻成功的SQL注入攻击可能造成的损害,您绝对应该采用最小权限原则。

设置符合您要求的系统应该非常简单。

我会使用你的exaple中的对象名称,除了我会使用下划线而不是minus。在对象名称中仅使用小写字母,下划线和数字是很好的,因为它会让您的生活更轻松。

/* create the database */
\c postgres postgres
CREATE DATABASE test_database WITH OWNER app_admin;
\c test_database postgres

/* drop public schema; other, less invasive option is to
   REVOKE ALL ON SCHEMA public FROM PUBLIC */
DROP SCHEMA public;
/* create an application schema */
CREATE SCHEMA app AUTHORIZATION app_admin;
/* further operations won't need superuser access */
\c test_database app_admin
/* allow app_user to access, but not create objects in the schema */
GRANT USAGE ON SCHEMA app TO app_user;

/* PUBLIC should not be allowed to execute functions created by app_admin */
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin
   REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;

/* assuming that app_user should be allowed to do anything
   with data in all tables in that schema, allow access for all
   objects that app_admin will create there */
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT SELECT, USAGE ON SEQUENCES TO app_user;
ALTER DEFAULT PRIVILEGES FOR ROLE app_admin IN SCHEMA app
   GRANT EXECUTE ON FUNCTIONS TO app_user;

但如果你采取最不严肃的原则,你应该单独授予表格权限,例如表格中不允许app_userDELETEUPDATE数据,用户无需这样做。

答案 1 :(得分:1)

对于Web应用程序,我将权限分为三个角色,每个角色都继承自其前任角色。

  1. 只读 - 用于SELECT查询和函数调用
  2. 插入 - 用于INSERT语句
  3. 更新和删除 - 这些主要用于管理,因为面向公众的前端应用程序通常不会修改或删除数据
  4. 这样,即使某些黑客设法进行SQL注入,他也只能使用所使用角色的权限,通常只有SELECT或INSERT。

    我的网络应用程序通常不需要像CREATE,DROP,TRUNCATE等更具侵入性的权限,因此我不会将这些权限授予网络应用程序。

    在第二个角色需要更新或删除某些内容的极少数情况下,我要么为该特定表授予权限,要么将代码放在使用SECURITY DEFINER创建的函数中。

    /** role_read is read-only with SELECT and EXECUTE */
    CREATE ROLE role_read;
    /** role_read_add adds INSERT */
    CREATE ROLE role_read_add;
    /** role_read_add_modify adds UPDATE and DELETE */
    CREATE ROLE role_read_add_modify;
    
    
    GRANT USAGE ON SCHEMA <schema> TO role_read;
    
    /** for existing objects */
    GRANT SELECT  ON ALL TABLES    IN SCHEMA <schema> TO role_read;
    GRANT SELECT  ON ALL SEQUENCES IN SCHEMA <schema> TO role_read;
    GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA <schema> TO role_read;
    
    /** for future objects */
    ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
        GRANT SELECT ON TABLES TO role_read;
    
    ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
        GRANT SELECT ON SEQUENCES TO role_read;
    
    /** role_read_add inherits from role_read */
    GRANT role_read TO role_read_add;
    
    /** for existing objects */
    GRANT INSERT ON ALL TABLES IN SCHEMA <schema> TO role_read_add;
    GRANT ALL ON ALL SEQUENCES IN SCHEMA <schema> TO role_read;
    
    /** for future objects */
    ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
        GRANT INSERT ON TABLES TO role_read_add;
    
    ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
        GRANT ALL ON SEQUENCES TO role_read_add;
    
    /** role_read_add_modify inherits from role_read_add */
    GRANT role_read_add TO role_read_add_modify;
    
    /** for existing objects */
    GRANT UPDATE, DELETE ON ALL TABLES IN SCHEMA <schema> 
        TO role_read_add_modify;
    
    /** for future objects */
    ALTER DEFAULT PRIVILEGES IN SCHEMA <schema>
        GRANT UPDATE, DELETE ON TABLES TO role_read_add_modify;