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

Applied Oracle Security: Developing Secure Database and Middleware Environments- P48 doc

10 267 1

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 274,21 KB

Nội dung

444 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence to this is application 4155, which allows end users to reset their passwords. It also includes a documented procedure to convert to and from a Runtime Only installation, so you don’t have to make this decision at install time. Technically, you could delete these applications in previous versions and achieve the same goal, but then you would be left with no ability to manage any settings within the APEX environment. Since there is no user interface in a Runtime Only installation, all instance configuration changes must occur using the APEX_INSTANCE_ADMIN API discussed earlier. Oracle SQL Developer 1.2.1 (shown in Figure 11-5) introduced tighter integration with APEX. A developer can now import/export applications and pages and modify application and page-level attributes simply by connecting to a schema associated with an APEX application using SQL Developer, and then right-clicking the application in the APEX tree. These features not only enhance productivity, but they also compliment a Runtime Only installation, as there is no APEX user interface in a Runtime Only installation. Calls to APEX_INSTANCE_ADMIN as well as SQL Developer features can also be tested with full installations of APEX to determine whether or not these interfaces will be acceptable before making the jump to a Runtime Only configuration. Additional security measures, such as removing the APEX administration interface, tend to introduce a level of inconvenience. This solution is a good example of adding security without sacrificing significant functionality or productivity. FIGURE 11-5 Oracle SQL Developer 1.2.1 interface Chapter 11: Web-centric Security in APEX 445 Obfuscate the APEX_PUBLIC_USER Password in dads.conf OHS uses a Database Access Descriptor (DAD), defined in $ORACLE_HOME/ohs/mod_plsql/ conf/dads.conf, to connect to the database. Each DAD includes connection information for the database, including the database username and password it should use. By default, the password is stored in clear text, which allows anyone who gains access to the file system to obtain all the information he or she needs to connect to the database using other tools. This security risk is easy to mitigate, but often overlooked. The solution is to use a utility included with OHS to “obfuscate” the password. The result is a hash of the password that only OHS can use to connect to the database. We use the term hash loosely as the technique and algorithms used are not public knowledge, but the basic concept is that of a hash. This example will only cover OHS version 10.1.3.3, but the same concepts apply to earlier versions. The obfuscation tool is called dadTool. pl and is located in $ORACLE_HOME/ohs/mod_plsql/conf/ along with its associated dadTool. README. The .README file details the setup of key environment variables, but unfortunately omits a key environment variable, PER5LIB, that will prevent dadTool.pl from working. The following settings are the ones successfully used on Oracle Enterprise Linux 5 for a BASH shell environment: ORACLE_HOME=/opt/oracle/product/ohs_10.1.3.3;export ORACLE_HOME PATH=$ORACLE_HOME/ohs/modplsql/conf:$PATH;export PATH PATH=$ORACLE_HOME/perl/bin:$PATH;export PATH LD_LIBRARY_PATH=$ORACLE_HOME/lib; export LD_LIBRARY_PATH PERL5LIB=$ORACLE_HOME/perl/lib; export PERL5LIB There are two very important changes to the default instructions to point out. On the second line, the .README indicates that the PATH should be $ORACLE_HOME/Apache/…, when the directory structure is actually $ORACLE_HOME/ohs/…. Depending on the operating system, this line could be different so pay attention to it. The second issue is the PERL5LIB environment variable as shown in the last line. This was never mentioned in the .README and caused an error in every system setup on this particular platform. Once the environment variables are set, simply navigate to $ORACLE_HOME/ohs/modplsql/conf/ and run the following command as indicated in the dadTool.README file: [oracle@aos conf]$ perl dadTool.pl -o All passwords successfully obfuscated. New obfuscations : 1 The following listing shows the “PlsqlDatabasePassword” setting before and after obfuscation: PlsqlDatabasePassword HelloWorld … PlsqlDatabasePassword @Bq6wJDT7YdtZok0nle12mEj= Network Topology Another key consideration when installing APEX is the network topology and physical separation of the HTTP server, database, and TNS (Transparent Network Substrate) Listener. It is a security architecture best practice to install the HTTP server on a physical machine that’s different from the database, because this topology provides several essential security benefits. The database and TNS Listener should reside completely within the corporate network with no network access exposed to the public Internet. It’s not uncommon to place the database behind an additional firewall so that it is not publicly accessible on the corporate intranet. The most common and desirable location for the HTTP server is on a separate server in your networks “demilitarized 446 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence zone,” or DMZ. A DMZ (Figure 11-6) is essentially a network that serves as a buffer zone between an internal private network and the public Internet. Firewall rules can be configured for a DMZ to allow TCP requests only on ports 80 and 443 (HTTP and HTTPS) through to the HTTP server. This type of configuration dramatically reduces the exposure of an APEX system to unauthorized attacks. When combined with the Runtime Only configuration, all external access to sensitive data and systems will be channeled through applications and tightly controlled by security administrators. One of the most popular topologies in which administrators are concerned about security is a public-facing Internet site connected to a non-public intranet database. Since the machine on which the HTTP server is installed will be directly exposed to the Internet, it is strongly encouraged that this machine be “hardened” as much as possible. While the following is not a comprehensive list, it offers a few suggestions to get you started hardening a Linux-based host: This should be a single-purpose server, whose only job is to act as an HTTP server, with the least amount of software installed as possible. Reducing the number of programs installed not only reduces the overall vulnerability of a server, but it also reduces the chance for incompatible versions of software and thus promotes more timely upgrades and patches to the operating system and other essential services on the machine. Uninstall or disable all nonessential services, especially network services such as NFS, IMAP/SMTP, and so on. Insecure, legacy services such as telnet, FTP, and VNC should be replaced with modern secure alternatives such as SSH, SCP/sFTP, and FreeNX. Disable remote access from common accounts such as root or guest, which are common attack vectors. In addition to setting hardware firewall rules at the network level, local firewall software such as iptables on Linux provide an additional layer of OS security. Install anti-virus and anti-rootkit software. All software, including the operating system, should be regularly patched to include the latest security fixes from various vendors. Oracle Enterprise Manager can be configured to connect to Oracle Metalink (http://metalink .oracle.com) and to check for updates to all Oracle software and then notify system administrators ■ ■ ■ ■ ■ ■ FIGURE 11-6 DMZ network topology Chapter 11: Web-centric Security in APEX 447 that updates are available. Another solution to consider is the Advanced Security option (ASO) of the database as it enables the encryption of the traffic between the HTTP server and the database, thus thwarting any packet inspection techniques that someone might use to view sensitive data. This would also allow internal network traffic from SQL*Plus or SQL Developer connections to be encrypted. Another topology to consider would be the external HTTP server acting only as a reverse proxy server that forwards all requests to OHS, shown in Figure 11-7. This is a common configuration when an organization has an existing HTTP server in their DMZ that does not have direct access to the database or is an HTTP server other than OHS/OAS that cannot directly render APEX pages. For example, assume that a fictitious company called Acme has a web site at www.acme.com (port 80) running on a vanilla version of Apache (without mod_plsql). The company wants to expose an APEX application to the Internet on port 80 with the same domain name. Apache can be configured to proxy all requests to a particular subdomain or virtual directory on to an additional HTTP server. So, any request to apex.acme.com is then forwarded on to an internal OHS, which in turn connects to the Oracle database. The path is simply reversed when APEX returns a response to the request. This configuration has an additional security benefit in that if the operating system of the external HTTP server is compromised, no Oracle client software is installed on that machine that would allow a hacker to connect directly to the database. Additionally, the TNS Listener and firewall on the database server should be configured to reject all connection attempts from this machine. mod_rewrite and APEX OHS is based on Apache, the most used web server on the Internet. Extensions to Apache are done through modules. OHS ships with many common modules already installed. Some of these modules are Oracle-specific, such as mod_plsql and mod_osso, while others are generally available to the Apache community. mod_rewrite is an open-source module that ships with FIGURE 11-7 Proxy server topology 448 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence OHS and is designed to allow administrators to rewrite, change, and redirect URLs as they are requested from the server. mod_rewrite uses a combination of regular expressions and environment variables to define rules for a particular URL pattern. The most common use of mod_rewrite is to redirect requests to old content that has moved to a new location. The following example redirects all requests for cat.html to dog.html: RewriteEngine on Options +FollowSymlinks RewriteRule ^/cat.html /dog.html [R,L] Developing and testing rules for mod_rewrite can be a challenging process since it’s difficult to see what rules were actually applied, and each change requires a restart of the HTTP server. Because of these challenges, you should develop and test mod_rewrite on an HTTP server that nobody else is using. You will also want to enable logging so that you can evaluate and verify what rules were applied. The following example enables logging to a file in the \temp (or /tmp) directory: RewriteEngine on Options +FollowSymlinks # The following syntax is used for Windows systems. # RewriteLog "c:\temp\rewrite.log" RewriteLog "/tmp/rewrite.log" RewriteLogLevel 3 RewriteRule ^/cat.html /dog.html [R,L] It’s also important to note that logging introduces a substantial performance penalty when it is enabled, so you should use it only when testing new rules and certainly not in production environments. mod_rewrite in Action Now that you have a basic understanding of mod_rewrite, let’s do something more useful with it. Earlier in this chapter, we talked about the new Runtime Only option in APEX. Another option to protect the development environment is to use a few mod_ rewrite rules. In this case, we will allow access to the APEX development environment from localhost (127.0.0.1) as well as a range of IP addresses: RewriteEngine on # The following directive is required for mod_rewrite on some platforms, # even though the concept of a symbolic link does not apply to APEX. Options +FollowSymlinks # Make sure the request is NOT for application 4155 RewriteCond %{REQUEST_URI}%{QUERY_STRING} !/pls/(apex|builder)/f?p=4155:.* # Is the request for an application in the range 4000-4999 RewriteCond %{REQUEST_URI}%{QUERY_STRING} /pls/(apex|builder)/f?p=(4[0-9]{3}:.*) # Make sure the IP of the requestor is not 127.0.0.1 or 10.11.12.0-255 RewriteCond %{REMOTE_ADDR} !^(127\.0\.0\.1|10\.11\.12\.[0-9]{1,3})$ # If the previous 3 conditions are true, return HTTP 403 "Forbidden" RewriteRule /pls/(apex|builder)/ - [F] Chapter 11: Web-centric Security in APEX 449 Let’s step through the rules line by line: 1. Application 4155 is a special case in that it allows end users to reset passwords, so we’ll exempt it from this policy by using a leading exclamation point that denotes “not” in regular expressions. 2. All applications in the range 4000–4999 match this rule. Notice that apex|builder is in parentheses because we have two DADs in this example: apex and builder. The pipe symbol between them indicates “or” in regular expressions. 3. The environment variable %{REMOTE_ADDR} returns the IP address of the client accessing the web server. This rule exempts localhost as well as any IP address in the range 10.11.12.0–255, so they will not be redirected. 4. If all three of the preceding conditions are met, this rule returns the HTTP 403 “Forbidden” code to the web browser. If any condition fails, the redirect will not occur and the user can access the development environment. It’s important to note that rules 1 and 3 use negative logic (!). Also note that the order of the first three rules is not important, since all three must return true for the redirect to occur. Many office networks use a different subnet for each floor or office section, which often creates a convenient way to allow only a certain group of employees access to the APEX development environment. This type of rule also works well for Internet-facing environments in which you want only internal IP addresses to access the development environment. Keep in mind that if your users are going through a proxy server to access your environment, the IP address that mod_rewrite will likely see is the IP address of the proxy server, not the user’s actual IP address. Another option for this solution is to use two HTTP servers, one available only to internal employees and the other in the DMZ that is accessed by Internet users. In this case, you could use the preceding rules on the server in the DMZ and simply omit the line that contains %{REMOTE_ ADDR}. Developers and administrators can access the development environment using the internal HTTP server that has no restrictions imposed by mod_rewrite, while the rules applied to the Internet-facing HTTP server would prevent anyone from accessing the development environment. The solutions in this section used the IP address as one of the components of the solution. It’s important to note that IP addresses can be spoofed in certain types of attacks, where a direct connection or immediate response is not required. A great example of this is a Denial of Services (DoS) attack, as the goal is to flood the host with requests, yet no response is required for the attack to succeed. The overarching theme of this book is defense in depth, and these solutions are merely one, not the only, line of defense. Prevent Web-based Attacks with mod_security Chapter 12 covers the concepts of SQL injection and cross-site scripting (XSS) from a programmatic perspective. It is critical that developers understand these concepts in detail and use appropriate coding practices to prevent them. However, in the interest of defense in depth, one instance-level security measure will prevent these types of attacks from getting through to the application code. SQL injection vulnerabilities occur when an attacker is able to pass full or partial SQL statements, such as drop table employees, into the application. XSS attacks are focused on an attacker inserting code, typically JavaScript, that will be executed by another user of the system. mod_security is an open source Apache module that is analogous to an application firewall. For SQL injection or XSS attacks to succeed, particularly in an APEX environment, nefarious code must pass through the OHS and on to the database. The general syntax for this code is well known 450 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence within the security community and therefore represents a signature that can indicate an attack. mod_security is designed to look for these types of signatures and stop them from doing any damage. When an HTTP request is made to an Apache-based server with mod_security enabled, mod_security intercepts the request very early in the processing sequence. The request is then run through a series of user-defined directives designed to look for SQL injection or XSS attacks. Following are a few example directives to illustrate this concept: # Ignore all SQL Injection for the APEX Builder, as a developer must be able # to enter SQL DML and DDL as well as JavaScript. # You could comment this out for production. SecFilterSelective ARG_p_flow_id "^4[0-9]{3}$" allow # SQL injection attacks – the following directive is all one line SecFilterSelective "ARGS|COOKIE_VALUES" "((select|grant|delete|insert|drop|alter| replace|truncate|update| create|rename|describe)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]+(from|into| table|database|index|view) [[:space:]]+[A-Z|a-z|0-9|\*| |\,]|UNION SELECT.*\'.*\'.*,[0-9].*INTO.*FROM)" # XSS attacks SecFilter "<[[:space:]]*script" # Mask our server signature SecServerSignature "Just Some Web Server" The first directive disables mod_security for the APEX development environment, because we must allow developers to submit JavaScript as well as SQL Data Manipulation Language (DML) and Data Definition Language (DDL). The next rule looks for database statements typically associated with SQL injection attacks. These statements are usually encoded in URL strings or submitted in HTML form elements such as text boxes or select lists, and then executed in the database. Obviously, a developer would prefer that the end user population be prevented from issuing arbitrary statements. The third rule blocks all requests containing an HTML <script …> tag, thus preventing a user from posting JavaScript into the application. The final directive serves to mask the signature of the HTTP server, which makes it much harder for an attacker to leverage a specific known vulnerability of the HTTP server. Thus far, we’ve looked at mod_security only as a tool to block malicious incoming requests. mod_security also offers the ability to inspect and filter output from web applications. A prime candidate for output filtering is any sensitive data of a particular pattern that could accidentally be “leaked” out to the public through a web application. For example, think about a web application built on a database that contains Social Security numbers (SSNs). While most developers would never intentionally display this type of data to the public, it’s all too easy to enter select * from table and accidentally return the SSN column. Since US SSNs and tax identification numbers conform to a very specific and unique pattern of ###-##- ####, it is easy to add a mod_security filter to check for them: SecFilterSelective OUTPUT "[[:digit:]]{3}-[[:digit:]]{2}-[[:digit:]]{4}" log,deny,status:500 Whenever a web application returns a string that conforms to this pattern, mod_security will trap the page and instead return an error page with an HTTP Status of “500 - Internal Server Error.” Another type of output that could be classified as a security risk are Oracle database errors. Error messages can give an attacker additional information about their target such as whether or Chapter 11: Web-centric Security in APEX 451 not a table or column exists. The following directive will trap Oracle errors before they are displayed to end users. Note that this also has the negative side-effect of making it difficult to detect and debug errors. SecFilterSelective OUTPUT "ORA\-[0-9]{5}" log,deny,status:500 Beginning with the release of Oracle 11g, the version of OHS available on the Database Companion CD is based on Apache 2.0. Prior versions of OHS are based on Apache 1.3. This change is important in the context of this section for two reasons: OHS 11g includes mod_security by default. The version is also important if you choose to install mod_security on your own, as it is dependent on the version of Apache. The version of mod_security included with OHS 11g is compatible with rules only for mod_security 1.9.3. Consequently, some of the new syntax for mod_security directives is not compatible with OHS 11g. If you want to use the latest rule sets, you can install the latest version of mod_security in OHS or install mod_security in another Apache HTTP server and proxy OHS through Apache, as described earlier in this chapter. SSL/TLS Techniques The goal of enabling Secure Sockets Layer (SSL) on OHS is to provide assurance that the host server is not being spoofed and to encrypt traffic in and out of the HTTP server. Recall the section “Encryption 101” from Chapter 2, where we discussed public key encryption and symmetric key encryption and mentioned that SSL uses a clever combination of public key and symmetric key encryption to do its thing. Here’s a quick review of SSL that will help you understand the purpose of the certificate files used to enable SSL: 1. An SSL encrypted session is initiated by a user’s Web browser requesting a URL that uses the HTTPS protocol, as in https://www.oracle.com. 2. The server then responds with some basic information, such as what ciphers it supports. The server also sends its certificate, which includes its public key signed by (the private key) of a known Certificate Authority. 3. The server’s certificate allows the client to verify that the server is indeed who it claims to be. If the user requested https://www.oracle.com, then the certificate should claim www. oracle.com to be the name of the server. If the certificate claimed a different name—say, www.orocle.com—a failure, or in the very least, a warning, would appear in the user’s browser. The actual validation comes because the user’s browser uses the public key of the known Certificate Authority to decrypt and validate the server’s information. If the Certificate Authority is unknown, the user would get a warning or the session would be rejected (depending on how the browser is configured). All of this prevents a nefarious person from pretending to be a legitimate site or redirecting a user from one site to another without the user realizing it. 4. The client’s browser creates a random symmetric key (or shared secret) that is used later with the symmetric encryption algorithm. It also chooses the symmetric encryption algorithm including key size from the list provided by the server. 5. If the client is not authenticating itself back to the server, the client then encrypts the symmetric key using the server’s public key and sends it back to the server. 6. The server then uses its private key to decrypt the symmetric key sent by the client. Since only the server is in possession of its private key, only it can decrypt the symmetric key sent by the user’s browser. This prevents an intermediary person from listening in on the conversation. 452 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence The first part of the handshake involving the server’s public and private keys is called public key cryptography and is computationally more expensive than symmetric key cryptography. However, it is the best practical way to encrypt initial communications between the client and server in which a key is not yet shared. Once the handshake is complete and they both posses the same shared key, all communication between the client and server uses symmetric key encryption, which is much less expensive. Encryption still adds overhead and will reduce the number of concurrent users that a HTTP server can support. The reduction in performance by enabling SSL is difficult to estimate, because it depends on many factors, including number and speed of CPUs, number of concurrent users, size of pages and static content, network latency, and OHS settings. In the optimal configuration of APEX in which the database and HTTP server are on different servers, the machine running OHS is typically incurring a very small load compared to the database server. This is expected, as the bulk of the work of APEX is done inside the database. If this is the case for your environment, enabling SSL is not likely to have an impact on performance as the database server is usually the limiting factor. The initial handshake is expensive and requires a minimum of five network round trips when compared to a non-SSL HTTP request that requires a minimum of two round trips. This could make the first page view substantially slower and is important to consider in environments with high network latency. Since OHS is based on Apache, any of the numerous SSL tuning guides for Apache are directly applicable, and SSL tuning is beyond the scope of this book. If you plan to have a large number of concurrent users, especially if your applications are on the public Internet, you should consider dedicated hardware solutions to offload the work of SSL encryption. For most intranet applications with well defined population of a few thousand users, software- based SSL encryption should be more than adequate. The two most common scenarios for SSL are either to encrypt all pages in a web application or to encrypt only certain pages. All financial institutions, at least those worthy of your trust, require SSL for all pages. Online retailers such as Amazon and eBay require SSL for login pages as well as any pages associated with the purchase of goods. Web applications that require less security typically use SSL only for login pages. Most popular web-based e-mail applications fall into this category. If your username and password were intercepted, a hacker could take over your e-mail account, so it’s import to protect these requests. Due to the additional performance requirements of SSL, discussed earlier, combined with the massive volume of traffic incurred by the most popular web mail applications, encrypting all pages would require a substantial investment in additional hardware. As with any changes to your architecture, you should benchmark SSL in your environment with your applications to determine whether the performance penalty is significant. Chances are, it won’t even be noticeable. Enable SSL in OHS The rest of this section will cover configuration topics for OHS 10g Release 3. In most cases, these steps are virtually identical to those for OHS 10g Release 2, with subtle differences such as directory structure. OHS 10g Release 3 includes a default Oracle Wallet with a signed certificate, and SSL is enabled by default. This is fine for testing purposes and allows developers to configure and test different SSL scenarios immediately. The default wallet should be treated like a self-signed certificate—great for testing but never for production. This is because your end users’ web browsers will not recognize the signing authority of this certificate and will either display a warning or block access to the site completely. The process of installing a valid certificate is well documented in the OHS and the OAS Administrators Guides, so we won’t repeat the details of the process here. However, a quick summary of the process is certainly helpful in understanding the big picture. Chapter 11: Web-centric Security in APEX 453 The first step is to navigate to $ORACLE_HOME/bin, where $ORACLE_HOME is the HTTP server home. If you are on a Linux or UNIX system, you should do this using a terminal in an X Window session: 1. Run Oracle Wallet Manager (OWM), a GUI tool that also has a command line interface. 2. Create a new wallet. 3. Create a new certificate request. This creates a private/public key pair. 4. Export the certificate request to a file. The certificate you are exporting is your public key. Your private key remains secured in the Oracle Wallet. 5. Send this certificate file to valid Certificate Authority. Choose one of the well-known Certificate Authorities, since its root public key is likely distributed with all modern web browsers. 6. The Certificate Authority will sign your public key using its private key. Typically, it will take steps to verify that you are who you claim to be. 7. The Certificate Authority will then return your signed public key. Since the key was signed by the authority’s private key, a client’s web browser can use its public key to verify that your public key was signed by a well-known, trusted signing authority, thus establishing a chain of trust. 8. The signed certificate is then imported into the Oracle Wallet. 9. Update ssl.conf to point to the new wallet location. To test SSL on OHS, we must first determine the port in which it is running. The easiest way to do this is to open the $ORACLE_HOME/ohs/conf/ssl.conf file, where $ORACLE_HOME is the home of OHS, not the Oracle home of the database. ssl.conf contains a directive in the form of “Listen 443”, where 443 is the port that is listening for HTTPS requests. It’s important to note that this port number is also in the Virtual Hosts section later in ssl.conf. If you change the port number, you must change it in both places. The following code is an excerpt of ssl.conf, with only the lines related to the port number shown: Listen 443 ## SSL Virtual Host Context ## <VirtualHost _default_:443> Another place to determine which ports are in use by OHS is the portlist.ini file in $ORACLE_ HOME/install/. Keep in mind that these port numbers were automatically assigned at installation time. This file will not reflect any changes to port numbers after installation. The following listing is the contents of portlist.ini: [Ports] Oracle HTTP Server port = 7780 Oracle HTTP Server Listen port = 7780 Oracle HTTP Server SSL port = 4458 Oracle HTTP Server Listen (SSL) port = 4458 Oracle HTTP Server Diagnostic port = 7202 Oracle HTTP Server Listen port = 7780 Oracle HTTP Server Listen (SSL) port = 4458 . the OHS and on to the database. The general syntax for this code is well known 450 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence within the security community and therefore. Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence The first part of the handshake involving the server’s public and private keys is called public key cryptography and is. used on Oracle Enterprise Linux 5 for a BASH shell environment: ORACLE_ HOME=/opt /oracle/ product/ohs_10.1.3.3;export ORACLE_ HOME PATH= $ORACLE_ HOME/ohs/modplsql/conf:$PATH;export PATH PATH= $ORACLE_ HOME/perl/bin:$PATH;export

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