PostgreSQL 15对用户权限这块进行了增强。默认情况下,不再设置public schema的CREATE权限。

2021年9月,PG15的版本提交了一个patch:默认情况下不再设置public schema的CREATE权限。该建议来自:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-1058。Commit为:https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=b073c3ccd06e4cb845e121387a43faa8c68a7b62

这对于普通用户来说(非超级用户)意味着什么呢?

先看下PG14的操作:

postgres=# SELECT version();
version
-------------------------------------------------------------------------------------------------------
PostgreSQL 14.5 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
(1 row)
postgres=# CREATE ROLE unprivileged WITH LOGIN;
CREATE ROLE
postgres=# CREATE DATABASE priv_test;
CREATE DATABASE
postgres=# \c priv_test
You are now connected to database "priv_test" as user "ads".
priv_test=# \dn+ public
List of schemas
Name  | Owner | Access privileges |      Description
--------+-------+-------------------+------------------------
public | ads   | ads=UC/ads       +| standard public schema
|       | =UC/ads           |
(1 row)

可以看到,public(访问权限中的第二行)具有USAGE(U)和CREATE(C)的权限。普通用户可以在public schema模式下创建表:

priv_test=# SET SESSION ROLE unprivileged;
SET
priv_test=> SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
priv_test=> CREATE TABLE priv_test (id INT);
CREATE TABLE
priv_test=> \dp priv_test
Access privileges
Schema |   Name    | Type  | Access privileges | Column privileges | Policies
--------+-----------+-------+-------------------+-------------------+----------
public | priv_test | table |                   |                   |
(1 row)

下面是PG15的操作及其影响:

postgres=# SELECT version();
version
----------------------------------------------------------------------------------------------------------
PostgreSQL 15beta3 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
(1 row)
postgres=# CREATE ROLE unprivileged WITH LOGIN;
CREATE ROLE
postgres=# CREATE DATABASE priv_test;
CREATE DATABASE
postgres=# \c priv_test
You are now connected to database "priv_test" as user "ads".
priv_test=# \dn+ public
List of schemas
Name  |       Owner       |           Access privileges            |      Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
|                   | =U/pg_database_owner                   |
(1 row)
缺少C(CREATE)。默认情况下,普通用户的CREATE TABLE不再工作:
priv_test=# SET SESSION ROLE unprivileged;
SET
priv_test=> SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
priv_test=> CREATE TABLE priv_test (id INT);
ERROR: permission denied for schema public
LINE 1: CREATE TABLE priv_test (id INT);

升级中如何应对这种情况呢?

这里有2种方法可以升级。当然还有其他更多方法,例如重新按照您的应用程序。但是处于本文目的,我们只关注数据从旧版本传输到新版本的方法。

1)从老版本(14或更老)中将数据dump出来,并恢复到新版本中(15及以上)

2)运行pg_upgrade.

两种方式的工作方式有点不同,我们看下细节:

Dump和Restore

使用自带的pg_dump工具来完成。最好使用自定义或者目录格式。并且需要使用较新版本(15)中的pg_dump来转储旧数据库:

/path/to/15/bin/pg_dump -F c -f /tmp/backup.dump priv_test

通过创建一个空数据库(使用template0作为源/模板)来完成恢复,然后使用pg_restore将转储恢复到新数据库中。

/path/to/15/bin/dropdb --if-exists priv_test
/path/to/15/bin/createdb -T template0 priv_test
/path/to/15/bin/pg_restore -d priv_test -e /tmp/backup.dump

然而:

priv_test=# \dn+ public
List of schemas
Name  |       Owner       |           Access privileges            |      Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
|                   | =U/pg_database_owner                   |
(1 row)

为什么public schema中具有“new”权限,而CREATE缺失?因为public模式包含在template0中,并被复制到新创建的数据库中,在PG15中,template0中的public模式具有“new”权限。我们看下:

priv_test=# SELECT datname, datallowconn FROM pg_database;
datname  | datallowconn
-----------+--------------p
postgres  | t
template1 | t
template0 | f
priv_test | t
(4 rows)
priv_test=# UPDATE pg_database SET datallowconn = TRUE WHERE datname = 'template0';
UPDATE 1
priv_test=# \c template0
You are now connected to database "template0" as user "ads".
template0=# \dn
List of schemas
Name  |       Owner
--------+-------------------
public | pg_database_owner
(1 row)
template0=# \dn+ public
List of schemas
Name  |       Owner       |           Access privileges            |      Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
|                   | =U/pg_database_owner                   |
(1 row)

如我们所见,template0中的public少了CREATE权限,然后将其复制到新数据库中。任何期望其他情况并依赖于普通用户可写的public应用程序都会遇到问题。可以通过在新数据库中为public添加CREATE权限来解决此问题:

priv_test=# GRANT CREATE ON SCHEMA public TO PUBLIC;
GRANT
priv_test=# \dn+ public
List of schemas
Name  |       Owner       |           Access privileges            |      Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
|                   | =UC/pg_database_owner                  |
(1 row)

如果您希望这是新数据库的默认值,就将此更改应用于template1.

pg_upgrade

升级的第二种方式是pg_upgrade。这会将目录从就数据库复制到新数据库中。然后复制或链接数据文件。这是将服务器升级到新版本的顺畅方法。

/path/to/14/bin/pg_ctl -m fast -D /data/14/data stop
/path/to/15/bin/pg_ctl -m fast -D /data/15/data stop
rm -rf /data/15/data/*
/path/to/15/bin/initdb --pgdata=/data/15/data
/path/to/15/bin/pg_upgrade -b /path/to/14/bin -B /path/to/15/bin -d /data/14/data -D /data/15/data -p 5454 -P 5455 -v

这将运行pg_upgrade,将14版本更新到15,之后public模式看起来与14相同:

priv_test=# \dn+ public
List of schemas
Name  | Owner | Access privileges |      Description
--------+-------+-------------------+------------------------
public | ads   | ads=UC/ads       +| standard public schema
|       | =UC/ads           |
(1 row)

PG不应用pg_database_owner也不用设置(撤销)“新”权限,所有内容都像以前一样被复制。如果想拥有15的新型为,需要从public撤销CREATE:

priv_test=# REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE

还可以将所有者设置为新的pg_database_owner:

priv_test=# ALTER SCHEMA public OWNER TO pg_database_owner;
ALTER SCHEMA
priv_test=# \dn+ public
List of schemas
Name  |       Owner       |           Access privileges            |      Description
--------+-------------------+----------------------------------------+------------------------
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+| standard public schema
|                   | =U/pg_database_owner                  |
(1 row)

总结

将 PostgreSQL 数据库从版本 <= 14 升级到版本 15 或更高版本会给public模式带来一些挑战。两种最常见的升级方式在处理更改时表现不同。

最好不要依赖可写的public模式。

原文

https://andreas.scherbaum.la/blog/archives/1120-Changes-to-the-public-schema-in-PostgreSQL-15-and-how-to-handle-upgrades.html

[译]PostgreSQL15 public shema权限增强相关推荐

  1. php面向对象受保护,php面向对象二之封装,protected ,public,private权限管理

    html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml ...

  2. [译]PostgreSQL15改进了UNIQUE和NULL

    PostgreSQL15改进了UNIQUE和NULL 最近发布了PG15 beta 2.本文关注对有NULL值的列进行UNIQUE约束的改进.虽然唯一约束的细小差别不如加速排序那样惊艳,但对于提高数据 ...

  3. 基类成员的public访问权限在派生类中变为_C++ 派生类的构造函数(学习笔记:第7章 06)...

    派生类的构造函数[1] 默认情况 基类的构造函数不被继承; 派生类需要定义自己的构造函数. C++11规定 可用using语句继承基类构造函数. 但是只能初始化从基类继承的成员. 派生类新增成员可以通 ...

  4. 基类成员的public访问权限在派生类中变为_C++ 派生类的构造函数举例:继承+组合(学习笔记:第7章 07)...

    派生类构造函数举例[1] 例7-4 派生类构造函数举例 #include 对程序的说明:构造函数的执行顺序 1.调用基类构造函数. 顺序按照它们被继承时声明的顺序(从左向右):Base2, Base1 ...

  5. 基类成员的public访问权限在派生类中变为_第17篇:C++继承中虚表的内存布局

    我们已经表明,非虚类的对象实例不包含虚指针,编译器在编译阶段也没有为非虚类没有构建虚表.而本篇我们会从简单的单继承链分析虚类中虚表构造过程和内存布局.这一切假定你有如下基础 对gdb调试器使用有一个比 ...

  6. 白塞尔公式_如何设计像乌塞尔这样的800人的婚礼

    白塞尔公式 As a design enthusiast, I've always dreamed about designing my "Yes I do" scene. Fin ...

  7. 【Linux】_Engineer_用户和组,ACL,磁盘分区,权限,进程管理,防火墙策略

    添加并测试用户账号 创建一个名为stu01的用户账号 检查/etc/passwd./etc/shadow文件的最后一行 检查/home/新增加的宿主目录(家目录) 为用户stu01设置一个密码(123 ...

  8. java——自定义字段转译

    前言 最近项目中经常或出现需要对查询数据的Date时间字段进行转String格式化,原有项目中是对每个查询的实体类中都添加了一个方法,专门用来进行时间格式化,感觉每个类都加,代码维护性不高不说,关键还 ...

  9. 安卓6.0运行时权限处理

    由于一直以来公司做的项目一直使用的目标版本是API22[安卓5.0],但是在API22上面会有很多的功能不能使用,例如软件管理权限,同时目前推荐的目标版本是API25也就是Android7.0,所以在 ...

最新文章

  1. 快速搞懂 SQL Server 的锁定和阻塞
  2. php 函数 数组 难学,php 数组的常用函数
  3. c# MEF框架(一 MEF简介及简单的Demo)
  4. Docker 镜像文件的导入和导出
  5. 字节小组长无意中得知整个部门的薪资,自己28K,手下却有35K,怎么办
  6. 用手机调试Android手机连上没反应解决办法
  7. TIF转PDF--itextpdf
  8. 便携式明渠流量计的功能特点及资质证书
  9. PHP 之建行龙支付-被扫(商家扫码客户二维码),扫码枪使用
  10. 架设服务器虚拟主机教程,web服务器虚拟主机(服务器搭建虚拟主机教程)
  11. 管理必备认知--员工素质模型:能愿知模型
  12. 全方位指导手把手教你实现自定义Spring Boot的 Starter公社
  13. rush learn note
  14. Qt opengl 实现图片的旋转
  15. java null转空_Java对象为空时,将null转换为 保存值为空的属性
  16. Spm12 入门教程
  17. sql服务器查看版本信息,怎么查看sql server的版本
  18. 电机磁电热多场耦合 matlab,兆瓦级高速永磁电机转子多场耦合强度分析
  19. 自学能考计算机专业吗,离散数学自学有可能吗?自学考试计算机专业是必考?...
  20. 「微信帐号amp;语音文件」结构分析-amr文件

热门文章

  1. 判定被7整除的简易方法
  2. 【其他】Tensorflow分布式使用简介
  3. Android开发者面试如何系统复习?成功入职阿里
  4. html 用css画出斑马线,CSS3实现斑马线、棋盘、格子复杂背景
  5. 后N天C语言,c语言计算一个日期的下一天后N天后的日期
  6. 外卖订单量预测异常报警模型实践
  7. canvas流星雨 数据流
  8. 锁屏上显示Activity
  9. 国际日期书写标准格式
  10. day36-MySQL基本SQL语句(下)