1. Trang chủ
  2. » Công Nghệ Thông Tin

Applied Oracle Security: Developing Secure Database and Middleware Environments- P37 docx

10 206 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Cấu trúc

  • Applied Oracle Security: Developing SecureDatabase and MiddlewareEnvironments

    • Contents

    • Foreword

    • Acknowledgments

    • Part I: Oracle Database Security New Features

      • 1 Security Blueprints and New Thinking

        • About This Book

        • Database Security Today

        • Security Motivators

        • Modeling Secure Schemas

        • Getting Started

        • Summary

      • 2 Transparent Data Encryption

        • Encryption 101

        • Encrypting Data Stored in the Database

        • The Transparent Data Encryption Solution

        • Tablespace Encryption: New with Oracle 11g

        • Oracle 11g Configuration

        • Summary

      • 3 Applied Auditing and Audit Vault

        • An Era of Governance

        • Auditing for Nonsecurity Reasons

        • The Audit Data Warehouse

        • What to Audit and When to Audit

        • The Audit Warehouse Becomes the Audit Vault

        • Installation Options

        • Summary

    • Part II: Oracle Database Vault

      • 4 Database Vault Introduction

        • The Security Gap

        • Database Vault Components

        • Installing Oracle Database Vault

        • Summary: Database Vault Is Differentiating Security

      • 5 Database Vault Fundamentals

        • Realms

        • Command Rules

        • Rule Sets

        • Factors

        • DBV Secure Application Roles

        • Summary

      • 6 Applied Database Vault for Custom Applications

        • Notional Database Applications Environment

        • From Requirements to Security Profile Design

        • Requirements Technique: Use Cases and Scenarios

        • Identify Coarse-Grained Security Profile

        • Identify Fine-Grained Security Profile

        • Identify DBV Factors Based on Business or System Conditions

        • Identify DBV Realms and Realm Objects Based on Objects

        • Identify Accounts, Roles, and DBV Realm Authorizations from Use Case Actors

        • Establish DBV Command Rules from Conditions

        • Establish DBV Secure Application Roles from Conditions

        • Summary

      • 7 Applied Database Vault for Existing Applications

        • Audit Capture Preparation

        • Capturing Audits

        • Analyzing the Audit Trail

        • Integrating DBV with Oracle Database Features

        • Advanced Monitoring and Alerting with a DBV Database

        • Summary

    • Part III: Identity Management

      • 8 Architecting Identity Management

        • Understanding the Problem with Identity Management

        • Architecting Identity Management

        • Oracle Identity Management Solutions

        • Summary

      • 9 Oracle Identity Manager

        • The User Provisioning Challenge

        • Oracle Identity Manager Overview

        • User Provisioning Processes

        • User Provisioning Integrations

        • Reconciliation Integrations

        • Compliance Solutions

        • OIM Deployment

        • Summary

      • 10 Oracle Directory Services

        • Identity Management and the LDAP Directory

        • Oracle Internet Directory

        • Directory Virtualization and Oracle Virtual Directory

        • OVD Applied

        • Summary

    • Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence

      • 11 Web-centric Security in APEX

        • Introduction to the APEX Environment

        • Securing an APEX Instance

        • Protecting the APEX Database Schemas

        • Summary

      • 12 Secure Coding Practices in APEX

        • Authentication and Authorization

        • SQL Injection

        • Cross-site Scripting

        • Leveraging Database Security Features

        • Summary

      • 13 Securing Access to Oracle BI

        • The Challenge in Securing BI

        • What Needs To Be Secured

        • Mechanics of Accessing Data with Oracle BI

        • Authentication and Authorization

        • Single Sign-On

        • Deploying in a Secure Environment

        • Securing the BI Cache

        • Public-facing Applications

        • Summary

      • 14 Securing Oracle BI Content and Data

        • Securing Web Catalog Content

        • Conveying Identity to the Database

        • Securing Data Presented by Oracle BI

        • Oracle BI and Database Vault

        • Auditing

        • BI Features with Security Implications

        • Summary

    • A: Using the Oracle BI Examples

      • Users and Groups

      • Database Preparations

        • Database Auditing

        • Database Scripts

      • Oracle BI Setup

        • Credential Store

        • BI Publisher Superuser

        • Other BI Publisher Configuration Steps

        • Sample BI Publisher Report

        • Scheduler Configuration

        • Usage Tracking

      • Recommend Testing

        • Oracle BI Tests

        • BI Publisher Tests

        • Oracle Delivers Tests

      • Sample Web Catalog Description

        • SH Dashboard

        • Utilities Dashboard

        • Other Dashboards

      • Sample RPD Descriptions

        • Common to All RPDs

        • Internal Authentication

        • Internal Authentication with Act as Proxy Enabled

        • Column-based Security

        • Table-based Authentication

        • Database Authentication

        • LDAP Authentication

        • SSO Integration

      • Summary

    • Index

      • A

      • B

      • C

      • D

      • E

      • F

      • G

      • H

      • I

      • J

      • K

      • L

      • M

      • N

      • O

      • P

      • Q

      • R

      • S

      • T

      • U

      • V

      • W

      • X

Nội dung

334 Part II: Oracle Database Vault proposals with rules stored for the sales managers who have the best expertise to respond to the proposal. Expression Filters use an Oracle operator EVALUATE in a SQL WHERE clause and again rely on function-based indexes for performance. Expression rules use a collection of distinct data attributes (called attribute sets) and Oracle object types. The PL/SQL APIs for creating these attribute sets and mapping them to the tables where the rule expressions will be stored requires two steps: First you must disable the Oracle Data Dictionary realm, and then you must disable the application realm (Sample DBV Application): diego_dbvmgr@aos> disable the Data Dictionary realm diego_dbvmgr@aos>BEGIN dbms_macadm.update_realm( realm_name => 'Oracle Data Dictionary' , description => 'Defines the realm for the Oracle Catalog' || ' schemas, SYS, SYSTEM, SYSMAN,MDSYS, etc.' || ' Also controls the ability to grant system' || ' privileges and database administrator roles.' , enabled => dbms_macutl.g_no , audit_options => dbms_macutl.g_realm_audit_fail ); END; / PL/SQL procedure successfully completed. diego_dbvmgr@aos> disable the application realm diego_dbvmgr@aos>BEGIN dbms_macadm.update_realm( realm_name => 'Sample DBV Application' , description => 'Sample to demonstrate feature integration with DBV' , enabled => dbms_macutl.g_no , audit_options => dbms_macutl.g_realm_audit_fail ); END; / PL/SQL procedure successfully completed. Now we can create our Expression Filter objects for the solicited proposal example: app_object_owner@aos> create an Oracle object type of rule attributes app_object_owner@aos>CREATE OR REPLACE TYPE proposal_type AS OBJECT ( industry VARCHAR2(30) , service VARCHAR2(30) , price_limit NUMBER ); / Type created. app_object_owner@aos> create the Expression Filter attribute set app_object_owner@aos> based on the object type app_object_owner@aos>BEGIN Chapter 7: Applied Database Vault for Existing Applications 335 dbms_expfil.create_attribute_set( attr_set => 'proposal_type' , from_type => 'YES'); END; / PL/SQL procedure successfully completed. app_object_owner@aos> create a table of sales managers app_object_owner@aos> and the rules expression column for app_object_owner@aos> their proposal skills app_object_owner@aos>CREATE TABLE sales_managers ( id NUMBER NOT NULL PRIMARY KEY , name VARCHAR2(30) , proposal_skills VARCHAR2(4000) ); Table created. app_object_owner@aos> map the attribute set to the table app_object_owner@aos>BEGIN dbms_expfil.assign_attribute_set ( attr_set => 'proposal_type', expr_tab => 'sales_managers', expr_col => 'proposal_skills'); END; / PL/SQL procedure successfully completed. Once the Expression Filter objects are in place, we can re-enable the Oracle Data Dictionary realm and then disable the application realm (Sample DBV Application): diego_dbvmgr@aos> disable the Data Dictionary realm diego_dbvmgr@aos>BEGIN dbms_macadm.update_realm( realm_name => 'Oracle Data Dictionary' , description => 'Defines the realm for the Oracle Catalog' || ' schemas, SYS, SYSTEM, SYSMAN,MDSYS, etc.' || ' Also controls the ability to grant system' || ' privileges and database administrator roles.' , enabled => dbms_macutl.g_yes , audit_options => dbms_macutl.g_realm_audit_fail ); END; / PL/SQL procedure successfully completed. diego_dbvmgr@aos> disable the application realm diego_dbvmgr@aos>BEGIN dbms_macadm.update_realm( realm_name => 'Sample DBV Application' , description => 'Sample to demonstrate feature integration with DBV' , enabled => dbms_macutl.g_yes 336 Part II: Oracle Database Vault , audit_options => dbms_macutl.g_realm_audit_fail ); END; / PL/SQL procedure successfully completed. With the Expression Filters configured and our realm protections back in place, we can populate our rule expressions and use the filters in SQL statements with the EVALUATE operator: app_object_owner@aos> create a few sales managers app_object_owner@aos> with their proposal skills rules app_object_owner@aos>INSERT INTO sales_managers VALUES (1, 'Mark', 'industry IN (''Oil'',''Mining'') AND price_limit >= 500000'); 1 row created. app_object_owner@aos>INSERT INTO sales_managers VALUES (2, 'Sandy', 'industry IN (''Retail'',''Food'') AND price_limit >= 500000'); 1 row created. app_object_owner@aos>INSERT INTO sales_managers VALUES (3, 'Roger', 'industry IN (''Retail'',''Food'') AND price_limit < 500000'); 1 row created. COMMIT; Commit complete. app_object_owner@aos> test the EVALUATE operator app_object_owner@aos>SELECT id, name FROM sales_managers WHERE EVALUATE ( sales_managers.proposal_skills, AnyData.convertObject( proposal_type('Retail','Marketing',100000) )) = 1; ID NAME 3 Roger 1 row selected. You can also embed DBV factor functions within the PL/SQL functions you create as user- defined functions that are supported in the Expression Filters technology. In the same way that the stored rule expressions for Expression Filters avoid the need to recode applications for new business rules, DBV factors embedded in the user-defined functions feature allow you to integrate security into Expression Filters logic without rewriting code. Oracle Streams Advanced Queuing Oracle Streams Advanced Queuing is a database feature that provides message queuing functionality that is integrated directly into the database. Message queuing involves one producer that enqueues (writes) a message into a queue and a consumer(s) that dequeues (reads) the message. This paradigm is typically used to integrate heterogeneous systems or physically remote Chapter 7: Applied Database Vault for Existing Applications 337 systems. The message payloads are generally stored in database tables to meet the objectives of message persistence and integrity (through backup/recovery), and to achieve performance goals. Message queue tables can be protected with DBV realms just like any other database object. For example, a new queue table created in the APP_OBJECT_OWNER account is automatically protected with the Sample DBV Application realm we just created: app_object_owner@aos> create the message payload objects and tables app_object_owner@aos> CREATE OR REPLACE TYPE aso_order AS OBJECT( order_num NUMBER , order_name VARCHAR2(60) , order_amount NUMBER , order_network VARCHAR2(100) ) / Type created. app_object_owner@aos> CREATE OR REPLACE TYPE aso_message AS OBJECT ( message_id RAW(16) , order_objects aso_order ) / Type created. app_object_owner@aos> CREATE TABLE aso_order_objects (message_object aso_message) / Table created. app_object_owner@aos> create the persistent message queue table app_object_owner@aos>BEGIN dbms_aqadm.create_queue_table( queue_table => 'aso_queue_table' , queue_payload_type => 'aso_order'); END; / PL/SQL procedure successfully completed. app_object_owner@aos> AQ creates tables app_object_owner@aos>SELECT table_name FROM user_tables WHERE table_name LIKE 'ASO%'; TABLE_NAME ASO_ORDER_OBJECTS ASO_QUEUE_TABLE 2 rows selected. If a privileged database administrator account, such as SYSTEM, attempts to access or manipulate these objects, the DBV realm protects these newly added objects: system@aos>SELECT * FROM app_object_owner.aso_queue_table; SELECT * FROM app_object_owner.aso_queue_table * ERROR at line 1: 338 Part II: Oracle Database Vault ORA-01031: insufficient privileges system@aos>DELETE app_object_owner.aso_queue_table; DELETE app_object_owner.aso_queue_table * ERROR at line 1: ORA-01031: insufficient privileges While we have protected the message stored in a queue, how do we add more protections on the consumers that can read the message? One approach is to leverage DBV factors as a form of a shared secret or as a filtering condition so that the information required to dequeue the message must be asserted through a DBV factor. If we consider the factors Certificate_Context and Connection_Type presented in Chapter 5, we might use them as a condition asserted by the message producer on enqueue so that only the appropriate consumers could dequeue the message. The approach is shown in the following code. First, the producer queues a message using a factor as one of the payload attributes: app_object_owner@aos>SELECT dvf.f$connection_type connection_type FROM dual; CONNECTION_TYPE CORPORATE_SSL app_object_owner@aos> queue the message using this factor app_object_owner@aos>DECLARE message_id number; l_msg_handle raw(16); l_enqueue_opts dbms_aq.enqueue_options_t; l_msg_props dbms_aq.message_properties_t; l_msg_object aso_order; BEGIN l_msg_object := aso_order(10 , 'SUN T5520' , 40000.00 ,DVF.F$CONNECTION_TYPE); l_enqueue_opts.VISIBILITY := DBMS_AQ.ON_COMMIT; dbms_aq.enqueue ( queue_name => 'aso_queue' , enqueue_options => l_enqueue_opts , message_properties => l_msg_props , payload => l_msg_object , msgid => l_msg_handle); COMMIT; END; / PL/SQL procedure successfully completed. Chapter 7: Applied Database Vault for Existing Applications 339 Next, only trusted consumers (such as the notional APP_USER account) can dequeue the message when the factor resolves to the correct value for the consumer’s session: app_user@aos>SELECT dvf.f$connection_type connection_type FROM dual; CONNECTION_TYPE CORPORATE_SSL app_user@aos> dequeue the message using this factor app_user@aos>SET SERVEROUT ON app_user@aos>DECLARE l_msg_handle raw(16); l_dequeue_opts dbms_aq.dequeue_options_t; l_msg_props dbms_aq.message_properties_t; l_msg_object app_object_owner.aso_order; BEGIN l_dequeue_opts.deq_condition := 'tab.user_data.order_network = ''' || DVF.F$CONNECTION_TYPE || ''''; l_dequeue_opts.dequeue_mode := dbms_aq.remove; wait for three (3) seconds to demo quickly l_dequeue_opts.wait := 3; dbms_aq.dequeue ( queue_name => 'app_object_owner.aso_queue' , dequeue_options => l_dequeue_opts , message_properties => l_msg_props , payload => l_msg_object , msgid => l_msg_handle); dbms_output.put_line('Dequeue done'); dbms_output.put_line('Order id :' || l_msg_object.order_num); dbms_output.put_line('Order name :' || l_msg_object.order_name); dbms_output.put_line('Order amount :' || l_msg_object.order_amount); dbms_output.put_line('Order network:' || l_msg_object.order_network); END; / Dequeue done Order id :10 Order name :SUN T5520 Order amount :40000 Order network:CORPORATE_SSL PL/SQL procedure successfully completed. 340 Part II: Oracle Database Vault Untrusted consumers cannot dequeue the message when the factor resolves to the incorrect value for the consumer’s session: app_user@aos>SELECT dvf.f$connection_type connection_type FROM dual; CONNECTION_TYPE OTHER app_user@aos> dequeue the message using this factor app_user@aos>SET SERVEROUT ON app_user@aos>DECLARE l_msg_handle raw(16); l_dequeue_opts dbms_aq.dequeue_options_t; l_msg_props dbms_aq.message_properties_t; l_msg_object app_object_owner.aso_order; BEGIN l_dequeue_opts.deq_condition := 'tab.user_data.order_network = ''' || DVF.F$CONNECTION_TYPE || ''''; l_dequeue_opts.dequeue_mode := dbms_aq.remove; wait for three (3) seconds to demo quickly l_dequeue_opts.wait := 3; dbms_aq.dequeue ( queue_name => 'app_object_owner.aso_queue' , dequeue_options => l_dequeue_opts , message_properties => l_msg_props , payload => l_msg_object , msgid => l_msg_handle); dbms_output.put_line('Dequeue done'); dbms_output.put_line('Order id :' || l_msg_object.order_num); dbms_output.put_line('Order name :' || l_msg_object.order_name); dbms_output.put_line('Order amount :' || l_msg_object.order_amount); dbms_output.put_line('Order network:' || l_msg_object.order_network); END; / DECLARE * ERROR at line 1: ORA-25228: timeout or end-of-fetch during message dequeue from APP_OBJECT_OWNER.ASO_QUEUE ORA-06512: at "SYS.DBMS_AQ", line 335 ORA-06512: at line 15 Chapter 7: Applied Database Vault for Existing Applications 341 In practice, you would want to wrap the dequeued functionality inside a PL/SQL procedure to hide the algorithm and timeout stack traces, and you’d use standard access controls on the queue. This example demonstrates a mechanism to ensure that data in the queue is dequeued (read) only in the correct context. In this example, the only correct context occurs when clients have a Connection_Type of CORPORATE_SSL. Transparent Data Encryption In Chapter 2 we introduced the encryption feature of the database that protects your data at the storage level so that sensitive information is not accessible using brute-force read methods on Oracle data files. Transparent Data Encryption (TDE) protects your sensitive information from being read at the OS layer. DBV’s realms and command rules can provide the same mechanism to prevent information from being read through the database’s SQL layer. The natural question to ask next is, why protect your information with DBV without protecting it with TDE? TIP If you protect your data with DBV, protect it with TDE as well. We created the Sample DBV Application realm and protected the objects in the APP_ OBJECT_OWNER account by issuing two PL/SQL command blocks. We can encrypt all data in the APP_OBJECT_OWNER.CUSTOMERS table with three commands by creating an encrypted tablespace and moving the table into the tablespace: jean_oper_dba@aos> create an encrypted tablespace jean_oper_dba@aos>CREATE TABLESPACE app_object_owner_ts DATAFILE '/opt/app/oracle/oradata/ensg/app_object_owner_encrypted.dbf' SIZE 10M AUTOEXTEND ON ENCRYPTION USING 'AES256' DEFAULT STORAGE(ENCRYPT); Tablespace created. give the APP_OBJECT_OWNER account storage quota on the encrypted tablespace CONNECT jim_acctmgr jean_oper_dba@aos>CONNECT jim_acctmgr Enter password: Connected. jim_acctmgr@aos>ALTER USER app_object_owner QUOTA UNLIMITED ON app_object_owner_ts; User altered. jim_acctmgr@aos> move the data table to the encrypted tablespace jim_acctmgr@aos>CONNECT app_object_owner Enter password: Connected. app_object_owner@aos>ALTER TABLE app_object_owner.customers MOVE TABLESPACE app_object_ts; Table altered. It really is that simple, so why not do it? 342 Part II: Oracle Database Vault Oracle Recovery Manager Oracle Recovery Manager (RMAN) is the Oracle-preferred method for efficiently backing up and recovering your Oracle database. RMAN is also integrated with the Enterprise Manager–based tools so that it can be instrumented remotely through a web browser. RMAN does not operate on the database for backups through the SQL layer, so it is not subject to DBV realm protections or DBV command rules to maintain integrity. When RMAN is coupled with TDE’s ability to encrypt tablespaces, we can ensure that an operational DBA cannot query or manipulate the sensitive data protected by DBV and cannot read the data files holding the sensitive data using TDE. However, the operational DBA can still perform backup and recovery of this data using RMAN, without seeing the data itself. jean_oper_dba@aos> attempt to query the data through the SQL layer jean_oper_dba@aos>SELECT last_name, credit_limit FROM app_object_owner.customers; 2 FROM app_object_owner.customers * ERROR at line 2: ORA-01031: insufficient privileges jean_oper_dba@aos>exit Disconnected from Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production With the Partitioning, Oracle Label Security, OLAP, Data Mining, Oracle Database Vault and Real Application Testing options [oracle@node1 ~]$ # Attempt to read the data files at the OS level [oracle@node1 ~]$ strings /opt/app/oracle/oradata/ensg/app_object_owner_encrypted.dbf }|{z ENSG APP_OBJECT_OWNER_TS [oracle@node1 ~]$ # backup up the encrypted tablespace with [oracle@node1 ~]$ # Oracle Recovery Manager [oracle@node1 ~]$ rman target jean_oper_dba/oracle Recovery Manager: Release 11.1.0.7.0 - Production on Thu Apr 23 18:46:16 2009 Copyright (c) 1982, 2007, Oracle. All rights reserved. connected to target database: ENSG (DBID=506519968) RMAN> configure channel device type disk format '/opt/app/oracle/rman/ora_df%t_s%s_ s%p'; using target database control file instead of recovery catalog old RMAN configuration parameters: CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/opt/app/oracle/rman/ora_df%t_s%s_s%p'; new RMAN configuration parameters: CONFIGURE CHANNEL DEVICE TYPE DISK FORMAT '/opt/app/oracle/rman/ora_df%t_s%s_s%p'; new RMAN configuration parameters are successfully stored RMAN> backup tablespace app_object_owner_ts ; Starting backup at 23-APR-09 allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=137 device type=DISK channel ORA_DISK_1: starting full datafile backup set channel ORA_DISK_1: specifying datafile(s) in backup set input datafile file number=00006 name=/opt/app/oracle/oradata/ensg/app_object_owner_ encrypted.dbf channel ORA_DISK_1: starting piece 1 at 23-APR-09 Chapter 7: Applied Database Vault for Existing Applications 343 channel ORA_DISK_1: finished piece 1 at 23-APR-09 piece handle=/opt/app/oracle/rman/ora_df684960426_s3_s1 tag=TAG20090423T184706 comment=NONE channel ORA_DISK_1: backup set complete, elapsed time: 00:00:01 Finished backup at 23-APR-09 RMAN> exit Recovery Manager complete. [oracle@node1 ~]$ # anything visible with the backup of the [oracle@node1 ~]$ # encrypted tablespace ? [oracle@node1 ~]$ strings /opt/app/oracle/rman/ora_df684960426_s3_s1 }|{z ENSG TAG20090423T184706 ENSG APP_OBJECT_OWNER_TS Gathering Statistics on Realm-protected Schemas The Oracle database is installed with a scheduler job named GATHER_STATS_JOB that will iterate over all database accounts to collect optimizer statistics. This ensures that accurate and up-to-date statistics are available to the optimizer. Statistics are collected automatically to provide the best possible performance for your applications without your having to perform the collection manually. On some releases and platforms, you may notice that this statistics collection fails due to realm protections on your database tables. Refer to Metalink document 735167.1 to determine whether a patch for your specific release and platform exists. If a patch is not available, you can request one and implement a work-around in the meantime. To work around this issue, you can set up a scheduler job that runs as the object-owner account to collect statistics using the following sample code block. Just change the ownname parameter to the object-owner account (APP_ OBJECT_OWNER) for your application. BEGIN dbms_stats.gather_schema_stats( ownname => 'APP_OBJECT_OWNER' , options => 'GATHER AUTO' , estimate_percent => dbms_stats.auto_sample_size , cascade => TRUE ); END; EXPLAIN PLAN on Realm-protected Schemas When a database session submits SELECT or DML statements to the database, the Oracle database optimizer generates a query execution plan to determine the most efficient method to perform the work. This execution plan will account for performance-enabling features of the database, such as partitions or indexes, that apply to the table(s) involved. The Oracle EXPLAIN PLAN feature allows your database administrator to view this plan in the same way that web-based services for driving directions let you find the quickest path from point A to point B, with turn-by-turn details and mileage between turns. The EXPLAIN PLAN feature might be used by your operational DBA in response to reports of performance issues from application developers or end users. With realm protections on the data tables, the DBA cannot use the AUTOTRACE capability in SQL*Plus. . it? 342 Part II: Oracle Database Vault Oracle Recovery Manager Oracle Recovery Manager (RMAN) is the Oracle- preferred method for efficiently backing up and recovering your Oracle database. RMAN. privileges jean_oper_dba@aos>exit Disconnected from Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production With the Partitioning, Oracle Label Security, OLAP, Data Mining, Oracle Database Vault and Real Application. rewriting code. Oracle Streams Advanced Queuing Oracle Streams Advanced Queuing is a database feature that provides message queuing functionality that is integrated directly into the database. Message

Ngày đăng: 06/07/2014, 23:20

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN