How to control who can see PostgreSQL function's source code

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:
函数内容比较敏感时, 如何提高函数内容的隐射或安全性呢?
1. 可以使用加密函数的方法来提高安全性. 需要安装额外的插件.
2. 可以使用C函数, 用户无法看到函数内容.
3. 如果以上方法无法在你的生产环境实施的话, 那么可以通过控制pg_proc的权限来控制谁可以看到函数内容.
例如, 我们这里创建一个测试函数 :
postgres=# create or replace function f() returns int as $$
postgres$# declare
postgres$#  a int := 10;
postgres$# begin
postgres$#  return a;
postgres$# end;
postgres$# $$ language plpgsql;
CREATE FUNCTION

函数内容存在pg_proc.prosrc字段中.
postgres=# select prosrc from pg_proc where proname='f';
    prosrc     
---------------
              +
 declare      +
  a int := 10;+
 begin        +
  return a;   +
 end;         +
 
(1 row)

创建一个普通用户, 因为pg_proc的权限给public角色了, 所以普通用户也可以查询到它的内容.
postgres=# create role test login;
CREATE ROLE
postgres=# \c postgres test
You are now connected to database "postgres" as user "test".
postgres=> select prosrc from pg_proc where proname='f';
    prosrc     
---------------
              +
 declare      +
  a int := 10;+
 begin        +
  return a;   +
 end;         +
 
(1 row)

仅仅回收prosrc字段的权限是不够的, 为什么呢? 参考
http://www.postgresql.org/docs/9.4/static/sql-revoke.html
postgres=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# revoke select(prosrc) on pg_proc from public;
REVOKE
postgres=# \c postgres test
You are now connected to database "postgres" as user "test".
postgres=> select prosrc from pg_proc where proname='f';
    prosrc     
---------------
              +
 declare      +
  a int := 10;+
 begin        +
  return a;   +
 end;         +
 
(1 row)

将pg_proc的权限从public回收即可.
postgres=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# revoke select on pg_proc from public;
REVOKE
postgres=# \c postgres test
You are now connected to database "postgres" as user "test".
postgres=> select prosrc from pg_proc where proname='f';
ERROR:  permission denied for relation pg_proc
postgres=> select proname from pg_proc where proname='f';
ERROR:  permission denied for relation pg_proc

但是这样做的话, 所有的普通用户都没有了查询权限, 包括不能列出函数名.
postgres=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# \du
                             List of roles
 Role name |                   Attributes                   | Member of 
-----------+------------------------------------------------+-----------
 d         |                                                | {}
 postgres  | Superuser, Create role, Create DB, Replication | {}
 test      |                                                | {}
postgres=> \df
ERROR:  permission denied for relation pg_proc

其他普通用户, 需要查询函数名, 必须赋予pg_proc的查询权限.
postgres=# grant select on pg_proc to d;
GRANT
postgres=# \c postgres d
You are now connected to database "postgres" as user "d".
postgres=> select prosrc from pg_proc where proname='f';
    prosrc     
---------------
              +
 declare      +
  a int := 10;+
 begin        +
  return a;   +
 end;         +
 
(1 row)

这样就控制了某个用户没有查询函数, 函数内容的权限.
postgres=> \c postgres test
You are now connected to database "postgres" as user "test".
postgres=> select prosrc from pg_proc where proname='f';
ERROR:  permission denied for relation pg_proc

如果要做到可以列出函数名, 但是不能查询函数内容. 怎么做呢?
首先我们要知道列函数用到什么QUERY
postgres@localhost-> psql -E
postgres=> \df
********* QUERY **********
SELECT n.nspname as "Schema",
  p.proname as "Name",
  pg_catalog.pg_get_function_result(p.oid) as "Result data type",
  pg_catalog.pg_get_function_arguments(p.oid) as "Argument data types",
 CASE
  WHEN p.proisagg THEN 'agg'
  WHEN p.proiswindow THEN 'window'
  WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
  ELSE 'normal'
 END as "Type"
FROM pg_catalog.pg_proc p
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE pg_catalog.pg_function_is_visible(p.oid)
      AND n.nspname <> 'pg_catalog'
      AND n.nspname <> 'information_schema'
ORDER BY 1, 2, 4;
**************************
ERROR:  permission denied for relation pg_proc

那么需要将除prosrc以外的所有字段(包括oid)都赋予给test用户即可.
postgres=# grant select(oid,proname,pronamespace,proowner,prolang,procost,prorows,provariadic,protransform,proisagg,proiswindow,prosecdef,proleakproof,proisstrict,proretset,provolatile,pronargs,pronargdefaults,prorettype,proargtypes,proallargtypes,proargmodes,proargnames,proargdefaults,probin,proconfig,proacl) on pg_proc to test;
GRANT
postgres=# \c postgres test
You are now connected to database "postgres" as user "test".

现在test用户可以列函数名, 但是不能看函数内容了.
postgres=> select proname from pg_proc limit 1;
 proname 
---------
 boolin
(1 row)

postgres=> select prosrc from pg_proc limit 1;
ERROR:  permission denied for relation pg_proc
postgres=> \df
                        List of functions
 Schema |          Name           |     Result data type      |                                                                     
                                                  Argument data types                                                               
                                                        |  Type  
--------+-------------------------+---------------------------+---------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------+--------
 public | dblink                  | SETOF record              | text                                                                
                                                                                                                                    
                                                        | normal
 public | dblink                  | SETOF record              | text, boolean

但是, 别高兴太早, 函数的内容不是这么查出来的, 而是通过pg_get_functiondef(oid)系统函数来获取的, 所以还需要回收这个系统函数的权限.
在回收权限前.
postgres=> select * from pg_get_functiondef(16649);
          pg_get_functiondef           
---------------------------------------
 CREATE OR REPLACE FUNCTION public.f()+
  RETURNS integer                     +
  LANGUAGE plpgsql                    +
 AS $function$                        +
 declare                              +
  a int := 10;                        +
 begin                                +
  return a;                           +
 end;                                 +
 $function$                           +
 
(1 row)
postgres=> \sf f
CREATE OR REPLACE FUNCTION public.f()
 RETURNS integer
 LANGUAGE plpgsql
AS $function$
declare
 a int := 10;
begin
 return a;
end;
$function$

回收权限后
postgres=# revoke execute on function pg_get_functiondef(oid) from public;
REVOKE
postgres=> \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# select oid from pg_proc where proname='f';
  oid  
-------
 16649
(1 row)
postgres=# \c postgres test
You are now connected to database "postgres" as user "test".
postgres=> \sf f
ERROR:  permission denied for function pg_get_functiondef
postgres=> select * from pg_get_functiondef(16649);
ERROR:  permission denied for function pg_get_functiondef

[小结]
通过权限来控制普通用户是否有查看函数内容的权限方法. 
第三步对于不同的PostgreSQL版本可能不一样, 请注意.
1. revoke select on pg_proc from public;
2. grant select on pg_proc to 需要查看函数内容权限的普通用户;
3. grant select(oid,proname,pronamespace,proowner,prolang,procost,prorows,provariadic,protransform,proisagg,proiswindow,prosecdef,proleakproof,proisstrict,proretset,provolatile,pronargs,pronargdefaults,prorettype,proargtypes,proallargtypes,proargmodes,proargnames,proargdefaults,probin,proconfig,proacl) on pg_proc to 不需要查看函数内容权限的普通用户;
4. revoke select(prosrc) on pg_proc from 不需要查看函数内容权限的普通用户;
5. 
postgres=# revoke execute on function pg_get_functiondef(oid) from public;
REVOKE
6. 
postgres=# grant execute on function pg_get_functiondef(oid) to 需要查看函数内容权限的普通用户;

目前PostgreSQL在对象权限这块控制还是过于粗燥, 不像Oracle做得很细, 用户间的权限控制是非常严格的.
而Postgres-XL则做了一定的修改, 是在parser层面做的, 可参考 : 
这也是一个路子.

[参考]
    When revoking privileges on a table, the corresponding column privileges (if any) are automatically revoked on each column of the table, as well. On the other hand, if a role has been granted privileges on a table, then revoking the same privileges from individual columns will have no effect.

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
弹性计算 缓存 Serverless
Serverless 应用引擎操作报错合集之阿里函数计算中我打开sd时遇到错误,信息为"Function instance exited unexpectedly(code 1, message:operation not permitted) with start command ' '."如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
311 6
|
4月前
|
JavaScript
【Azure Function App】Nodejs Function遇见WorkerProcessExitException : node exited with code -1073740791 (0xC0000409) 错误
【Azure Function App】Nodejs Function遇见WorkerProcessExitException : node exited with code -1073740791 (0xC0000409) 错误
|
5月前
|
分布式计算 DataWorks 关系型数据库
DataWorks操作报错合集之使用连接串模式新增PostgreSQL数据源时遇到了报错"not support data sync channel, error code: 0001",该怎么办
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
7月前
|
弹性计算 Dubbo Serverless
Serverless 应用引擎操作报错合集之阿里函数计算中配置完fc,出现‘Function instance exited unexpectedly(code 1, message:operation not permitted) with start command 'npm run start '. 报错如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
225 5
|
7月前
|
Java 中间件 Serverless
Serverless 应用引擎操作报错合集之在阿里函数计算中,云函数怎么一直报错Function instance exited unexpectedly(code 1, message:operation not permitted) with start command 'php server.php '.如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
174 2
|
编译器 Serverless Go
Fail to start function, Code:1
Fail to start function, Code:1
70 2
|
人工智能 自然语言处理 小程序
cloud function service error code -501000, error message 找不到对应的FunctionName.; at cloud.callFunction
cloud function service error code -501000, error message 找不到对应的FunctionName.; at cloud.callFunction
91 0
|
PHP
漏刻有时环境部署:php安装提示Can‘t use function return value in write context
漏刻有时环境部署:php安装提示Can‘t use function return value in write context
69 0
|
数据可视化 PHP
漏刻有时数据可视化大屏常见问题(1): Can’t use function return value in write context
漏刻有时数据可视化大屏常见问题(1): Can’t use function return value in write context
74 0
|
Linux
编译OpenJDK8:error: control reaches end of non-void function [-Werror=return-type]
编译OpenJDK8:error: control reaches end of non-void function [-Werror=return-type]
194 0