V-72911
Severity: Medium
Generated
2019-05-20 15:48:11.984914
Status
PostgreSQL must isolate security functions from non-security functions.
NIST 800-53
STIG # | Description | Result |
---|---|---|
SC-3 | SC-3: Security Function Isolation | passed |
Guidance
An isolation boundary provides access control and protects the integrity of the hardware, software, and firmware that perform security functions. Security functions are the hardware, software, and/or firmware of the information system responsible for enforcing the system security policy and supporting the isolation of code and data on which the protection is based. Developers and implementers can increase the assurance in security functions by employing well-defined security policy models; structured, disciplined, and rigorous hardware and software development techniques; and sound system/security engineering principles. Database Management Systems typically separate security functionality from non-security functionality via separate databases or schemas. Database objects or code implementing security functionality should not be commingled with objects or code implementing application logic. When security and non-security functionality are commingled, users who have access to non-security functionality may be able to access security functionality.
Check
Check PostgreSQL settings to determine whether objects or code implementing security functionality are located in a separate security domain, such as a separate database or schema created specifically for security functionality. By default, all objects in pg_catalog and information_schema are owned by the database administrator. To check the access controls for those schemas, as the database administrator (shown here as “postgres”), run the following commands to review the access privileges granted on the data dictionary and security tables, views, sequences, functions and trigger procedures: $ sudo su - postgres $ psql -x -c “\dp pg_catalog.“ $ psql -x -c “\dp information_schema.“ Repeat the \dp statements for any additional schemas that contain locally defined security objects.
Repeat using \df+. to review ownership of PostgreSQL functions: $ sudo su - postgres $ psql -x -c “\df+ pg_catalog.“ $ psql -x -c “\df+ information_schema.“ Refer to the PostgreSQL online documentation for GRANT for help in interpreting the Access Privileges column in the output from \du. Note that an entry starting with an equals sign indicates privileges granted to Public (all users). By default, most of the tables and views in the pg_catalog and information_schema schemas can be read by Public. If any user besides the database administrator(s) is listed in access privileges and not documented, this is a finding. If security-related database objects or code are not kept separate, this is a finding.
Fix
Do not locate security-related database objects with application tables or schema. Review any site-specific applications security modules built into the database: determine what schema they are located in and take appropriate action. Do not grant access to pg_catalog or information_schema to anyone but the database administrator(s). Access to the database administrator account(s) must not be granted to anyone without official approval.
Test Results
Result | |
---|---|
PostgreSQL query: SELECT n.nspname, c.relname, c.relkind, pg_catalog.array_to_string(c.relacl, E',') FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f') AND n.nspname ~ '^(pg_catalog)$' AND pg_catalog.array_to_string(c.relacl, E',') !~ '^(((vcap=[arwdDxtU]+|=[r]+)\/\w+,?)+|)$' AND c.relname NOT IN ('pg_settings'); output should eq "" | passed |
PostgreSQL query: SELECT n.nspname, p.proname, pg_catalog.pg_get_userbyid(n.nspowner) FROM pg_catalog.pg_proc p LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname ~ '^(pg_catalog)$' AND pg_catalog.pg_get_userbyid(n.nspowner) <> 'vcap'; output should eq "" | passed |
PostgreSQL query: SELECT n.nspname, c.relname, c.relkind, pg_catalog.array_to_string(c.relacl, E',') FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f') AND n.nspname ~ '^(information_schema)$' AND pg_catalog.array_to_string(c.relacl, E',') !~ '^(((vcap=[arwdDxtU]+|=[r]+)\/\w+,?)+|)$' AND c.relname NOT IN ('pg_settings'); output should eq "" | passed |
PostgreSQL query: SELECT n.nspname, p.proname, pg_catalog.pg_get_userbyid(n.nspowner) FROM pg_catalog.pg_proc p LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname ~ '^(information_schema)$' AND pg_catalog.pg_get_userbyid(n.nspowner) <> 'vcap'; output should eq "" | passed |
Code
control "V-72911" do
title "PostgreSQL must isolate security functions from non-security functions."
desc "An isolation boundary provides access control and protects the integrity
of the hardware, software, and firmware that perform security functions.
Security functions are the hardware, software, and/or firmware of the
information system responsible for enforcing the system security policy and
supporting the isolation of code and data on which the protection is based.
Developers and implementers can increase the assurance in security functions
by employing well-defined security policy models; structured, disciplined, and
rigorous hardware and software development techniques; and sound system/security
engineering principles.
Database Management Systems typically separate security functionality from
non-security functionality via separate databases or schemas. Database objects
or code implementing security functionality should not be commingled with
objects or code implementing application logic. When security and non-security
functionality are commingled, users who have access to non-security
functionality may be able to access security functionality."
impact 0.5
tag "severity": "medium"
tag "gtitle": "SRG-APP-000233-DB-000124"
tag "gid": "V-72911"
tag "rid": "SV-87563r1_rule"
tag "stig_id": "PGS9-00-004000"
tag "cci": "CCI-001084"
tag "nist": ["SC-3", "Rev_4"]
tag "check": "Check PostgreSQL settings to determine whether objects or code
implementing security functionality are located in a separate security domain,
such as a separate database or schema created specifically for security
functionality.
By default, all objects in pg_catalog and information_schema are owned by the
database administrator.
To check the access controls for those schemas, as the database administrator
(shown here as \"postgres\"), run the following commands to review the access
privileges granted on the data dictionary and security tables, views,
sequences, functions and trigger procedures:
$ sudo su - postgres
$ psql -x -c \"\\dp pg_catalog.*\"
$ psql -x -c \"\\dp information_schema.*\"
Repeat the \\dp statements for any additional schemas that contain locally
defined security objects.
Repeat using \\df+*.* to review ownership of
PostgreSQL functions:
$ sudo su - postgres
$ psql -x -c \"\\df+ pg_catalog.*\"
$ psql -x -c \"\\df+ information_schema.*\"
Refer to the PostgreSQL online documentation for GRANT for help in
interpreting the Access Privileges column in the output from \\du. Note that
an entry starting with an equals sign indicates privileges granted to Public
(all users). By default, most of the tables and views in the pg_catalog and
information_schema schemas can be read by Public.
If any user besides the database administrator(s) is listed in access
privileges and not documented, this is a finding.
If security-related database objects or code are not kept separate, this is a
finding."
tag "fix": "Do not locate security-related database objects with application
tables or schema.
Review any site-specific applications security modules built into the
database: determine what schema they are located in and take appropriate
action.
Do not grant access to pg_catalog or information_schema to anyone but the
database administrator(s). Access to the database administrator account(s)
must not be granted to anyone without official approval."
exceptions = "#{PG_OBJECT_EXCEPTIONS.map { |e| "'#{e}'" }.join(',')}"
object_acl = "^(((#{PG_OWNER}=[#{PG_OBJECT_GRANTED_PRIVILEGES}]+|"\
"=[#{PG_OBJECT_PUBLIC_PRIVILEGES}]+)\\/\\w+,?)+|)$"
schemas = ['pg_catalog', 'information_schema']
sql = postgres_session(PG_DBA, PG_DBA_PASSWORD, PG_HOST)
schemas.each do |schema|
objects_sql = "SELECT n.nspname, c.relname, c.relkind, "\
"pg_catalog.array_to_string(c.relacl, E',') FROM pg_catalog.pg_class c "\
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "\
"WHERE c.relkind IN ('r', 'v', 'm', 'S', 'f') "\
"AND n.nspname ~ '^(#{schema})$' "\
"AND pg_catalog.array_to_string(c.relacl, E',') !~ '#{object_acl}' "\
"AND c.relname NOT IN (#{exceptions});"
describe sql.query(objects_sql, [PG_DB]) do
its('output') { should eq '' }
end
functions_sql = "SELECT n.nspname, p.proname, "\
"pg_catalog.pg_get_userbyid(n.nspowner) "\
"FROM pg_catalog.pg_proc p "\
"LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace "\
"WHERE n.nspname ~ '^(#{schema})$' "\
"AND pg_catalog.pg_get_userbyid(n.nspowner) <> '#{PG_OWNER}';"
describe sql.query(functions_sql, [PG_DB]) do
its('output') { should eq '' }
end
end
end