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

Applied Oracle Security: Developing Secure Database and Middleware Environments- P51 pdf

10 284 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 400,32 KB

Nội dung

474 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence Kochhar - 17000 De Haan - 17000 Hunold - 9000 Ernst - 6000 Austin - 4800 Pataballa - 4800 Gietz - 8300 107 Rows Returned Now we can see all 107 rows! How did this happen? 1. By including the single quote after Grant, the where predicate has the correct syntax. 2. Adding or 1 = 1 essentially negates the where predicate and returns every row since 1 will always equal 1. 3. The at the end of the statement is the comment operator in Oracle SQL, which comments out the trailing single quote that is in the original procedure. Remember that we already closed the quote in step 1. The addition of this predicate completely changes the result set of the query. Instead of simply passing different last names to the procedure, we are able to construct parameters that will modify the structure of the query. The more an attacker knows about a system, the more effectively he can plan an attack. In the next example, we will pass a more sophisticated parameter to the same procedure to start investigating the data dictionary views. hr@aos> exec sql_injection(q'!ZZZ' union select null,null, table_name last_name,null,null,null,null,null,null,null,null from user_tables !'); COUNTRIES - DEPARTMENTS - EMPLOYEES - JOBS - JOB_HISTORY - LOCATIONS - REGIONS - 7 Rows Returned Here’s the breakdown of this attack: 1. The first part of the parameter is ZZZ’. This simply returns no rows from the employees table and closes the first quote. This was intentional since we already have all of the rows in the preceding example. 2. Next, we union in our own query. The syntax of a union operator is such that both queries need to have the same number and type of columns, so an attacker would need to keep adding null columns until he received a result. 3. Once again, we comment out the trailing single quote since we already closed it in step 1. A variation on this attack might be to query the USER_TAB_COLUMNS table to find all the columns in the employees table. We could then union in our own query of the employees table Chapter 12: Secure Coding Practices in APEX 475 to select columns that we were not intended to see, such as Social Security Number or Government Identification Number. Example 2: The Right Way The fatal flaw with the procedure in the preceding example is that instead of using bind variables, it glues a query together based on values passed in by the user, allowing an attacker to change the structure and the semantics of the query. Bind variables prevent SQL injection by allowing the values of predicates to change at runtime, yet the structure of the query cannot change. The following example is a modified version of the preceding example implemented using bind variables: create or replace procedure sql_injection_prevented( p_last_name in varchar2) is type employee_record is table of employees%ROWTYPE; emp_rec employee_record := employee_record(); x varchar2(32767); begin x := q'!select * from employees where last_name = :last_name !'; execute immediate x bulk collect into emp_rec using p_last_name; for i in emp_rec.first emp_rec.last loop dbms_output.put(emp_rec(i).last_name||' - '); dbms_output.put_line(emp_rec(i).salary); end loop; dbms_output.put_line(emp_rec.count||' Rows Returned'); end sql_injection_prevented; / Take a close look at the query string defined in the variable X. Because it uses a bind variable, :last_name, the query is first parsed without the actual value of p_last_name substituted for the bind variable last_name. The SQL parser knows during the parse phase that this query has only one predicate and that the only acceptable value for last_name is a character string that represents a value. It is impossible to add any structures such as an OR predicate that changes structure of the query. To prove this, let’s use a few of the tests from our previous example. This procedure works as expected when we call it with a last name: hr@aos> exec sql_injection_prevented(q'!Grant!'); Grant - 2600 Grant - 7000 2 Rows Returned Now let’s try one of our SQL injection techniques: hr@aos> exec sql_injection_prevented(q'!Grant' or 1 = 1 !'); BEGIN sql_injection_prevented(q'!Grant' or 1 = 1 !'); END; * ERROR at line 1: 476 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence ORA-06502: PL/SQL: numeric or value error ORA-06512: at "HR.SQL_INJECTION_PREVENTED", line 1 ORA-06512: at line 1 This time we receive a “numeric or value error” since the string we passed in is not a valid string when searching for LAST_NAME. Now that you fully understand the concept of SQL injection, let’s talk about how it applies to APEX. Bind variables are remarkably easy to use in APEX since you do not have to write extra code to bind the values of those variables. You can simply reference the APEX items using bind variable syntax. The following examples demonstrate a SQL query and an insert statement as a developer would use them in APEX: This query is used in a report region select first_name,last_name from employees where instr(upper(last_name),upper(nvl(:P1_SEARCH,last_name))) > 0 This insert statement is used in a page process insert into employees (first_name,last_name) values (:P2_FIRST_NAME,:P2_LAST_NAME) returning employee_id into :P2_NEW_EMPLOYEE_ID; Note that in both examples, bind variable syntax is used to reference items. It is possible to reference APEX items using &ITEM_NAME. syntax, which treats them as a string, not a bind variable. For example, in the first query, we could have used &P1_SEARCH. instead of :P1_SEARCH. In that case, a nefarious user could inject carefully constructed code, through either the URL or the search box, which would modify the semantics of the query at runtime. The documentation, tutorials, and examples used throughout the APEX community encourage bind variable syntax. However, it is still possible for a developer who does not understand the difference to use the wrong syntax. Fortunately, the wrong syntax is substantially more complex than the right syntax when you add in the concatenation operators, so the secure way is actually the easy way. Cross-site Scripting Cross-site scripting (XSS) is a type of web exploit that affects every web development technology by attempting to execute client-side code, typically JavaScript, in a user’s browser that was not included by the original developers of the application. For example, suppose a JavaScript function was executed on the Accounts page of your online banking application that searched for your account numbers on that page, and then posted those account numbers to some other web server controlled by a hacker. Obviously, the developers of the banking application would never create such a function, but if someone else were able to “inject” this function into your browser session or the page itself, the consequences could be catastrophic. Of the several different types of XSS attacks, the most obvious one in the context of APEX is called “persistent.” The persistent attack takes advantage of applications that have a database backend and that allow end users to save text that includes JavaScript, that will then be displayed by another user (as shown in Figure 12-5). Let’s look at another example in an effort to clarify the vulnerability. Imagine a timecard system or reporting application written in APEX that allowed users to enter the number of hours they worked along with some comments about those hours and a display of their year-to-date earnings. A newly submitted timecard would be routed to a person’s manager Chapter 12: Secure Coding Practices in APEX 477 for approval. The manager could see all of her employees’ hours, comments, and salaries. So far, the application works as intended. Now imagine that in my comments for this week, I include JavaScript that sends all the data displayed on a page to a web server that I control. When my manager views my timecard and my comments, she is unknowingly executing my JavaScript stored in the comments field, which sends the salary of everyone in my group to a server that I control. If I knew that the business rules of the system were such that overtime of more than 20 hours goes up to our group vice president for approval, I could wait for a week when I had more than 20 hours of overtime to inject my code, thus gaining access to the salaries of everyone in the whole organization. Who would have thought that a simple comments field could do so much damage? Hopefully, you’re now asking yourself, What can I do to prevent this? Fortunately, APEX includes features to help developers mitigate the risk of XSS. To summarize, the behavior we are trying to prevent is the ability for one user to submit JavaScript that will be displayed and therefore executed by other users. The most common APEX objects that display data are regions of type Report and APEX page items. When a new Standard Report is created based on a SQL query in APEX 3.2, the default column type for every column is called Standard Column. Unfortunately, this type of column is vulnerable to XSS. To prevent XSS, a developer must change this column type to Display as Text (escape special characters, does not save state). Future versions of APEX will likely change the default column type to the more secure version. The new type of APEX reports, called Interactive Reports, use the secure column type by default. This same concept applies to APEX page items. If a developer chooses an item of type Display As Text, any JavaScript code that is stored in session state for that item will be executed when the page is displayed. To prevent this, a developer should choose items of type Display As Text (escape special characters, does not save state), as shown in Figure 12-6. In the case of the Report Column type and the APEX page item type, the “escape special characters” aspect is key, because it will send the HTML character codes for the less-than and greater-than signs—&lt; and &gt;, respectively—to the browser, not the characters < and >. The escaping of such markup-sensitive characters will cause the browser to render the actual characters, rather than interpret them as HTML. Using this technique will prevent data containing <script>…</script> from being interpreted as executable JavaScript. One of the best ways for a developer to understand a security vulnerability is to intentionally create an example that is vulnerable, and then re-create the same example in a secure way. To that end, the following is a simple two-page APEX application that demonstrates the insecure and secure report column types and page item types. The following code, saved in a database table, simply writes a line of text onto a web page. The message is written in Unicode character codes so that it is unreadable unless the JavaScript function is executed: <script type="text/JavaScript"> document.write(String.fromCharCode(88,83,83,32,86,117,108,110,101,114,97,98,108,101)); </script> FIGURE 12-5 Persistent XSS 478 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence The report on the page has two comments columns that display the previous JavaScript function. The first column, Comments - Secure, is set to the secure type of Display as Text (escape special characters, does not save state). The second column, Comments - Insecure, is set to the type Standard Column. As you can see in Figure 12-7, the first column shows the JavaScript function in its entirety, but does not execute it, while the second column is actually executing the JavaScript as you can read the phrase “XSS Vulnerable” in the comments. The developer of this application anticipated that users would enter only comments about an employee. However, it was trivial to add a bit of JavaScript that is now executed by any other user who views the report. URL Tampering In the earliest days of the internet web pages were primarily, a static, read-only medium used to share information. The most interaction a user had with a web application was clicking a link. Today, modern web applications have evolved to the point that there is an almost continuous two- way stream of information between a user’s web browser and the application server. I’d like to emphasize “almost continuous” because it’s important to understand the true nature of the HTTP Protocol as it relates to modern web applications. HTTP is a stateless protocol as a persistent connection is not maintained between the client web browser and the HTTP server. In contrast, traditional client-server applications maintain a persistent connection between the client and the server. The actions of the HTTP protocol are often defined in terms of request, response. I like to add a third term and describe it as request, response, disconnect. The emphasis on “disconnect” helps developers understand the true nature of the technology they are working with. Consider the impact of removing the network connection would have on a web application compared to a client-server application. The stateful client-server application would know immediately if the FIGURE 12-6 Report column types Chapter 12: Secure Coding Practices in APEX 479 connection were severed whereas the web application would have no knowledge of this action. Obviously, the end user in the web scenario would know when they clicked a link or posted a form and received no response, but the HTTP Server would have no knowledge of this. Now that we have a better understanding of the stateless nature of a web application, let’s talk about how APEX maintains session state. When a user requests a page from an APEX application, the APEX engine checks to see if this is the first request from this user in this browser session. If it is the first request, APEX assigns a new, unique number for this session. For brevity, we’ll refer to this unique user session identifier as the Session ID. When you are using an APEX application, including the APEX Development Environment, notice the third parameter in the colon delimited list in the URL is a long seemingly random number. This number is also stored in a hidden form field on every page called pInstance. APEX also passes variables, such as search criteria, as parameters in the URL when the operation is an HTTP GET. One of the most convenient aspects of APEX for developers is that this session state is automatically managed for them in database tables. Once a value is set for an APEX Page or Application Item, the value of this item is maintained for the duration of the user’s session. One simple, yet security-friendly benefit to this is realized when passing data between pages. If you as a developer set the value of an item on page 1, you can refer to it on any other page in the application without the need to constantly pass it through the URL. FIGURE 12-7 XSS example report output 480 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence A classic example of passing session state through the URL is the “Report and Form on a Table” generated by a wizard within APEX. The wizard builds a report page that shows the rows in a database table with an edit link next to each row. When users click on the edit link they are taken to the form page where they can edit the data in that row, as shown in Figure 12-8. The primary key of the table is passed as a parameter in the URL. The query on the form page uses that primary key as a query predicate to select the desired row. In our example, what would happen if a user simply changed the value of the primary key in the URL (aka URL tampering)? If the user chose a value that matched another row in the table, that row would appear in the form. This raises an obvious security concern as end users are able to change the value used in the query predicate at will. Imagine now that the developer in this example wanted to limit the rows a user could edit by simply limiting the rows shown on the report page. If there is no row to click, how can a user edit that row? This false assumption by a developer could easily allow a user to gain access to data he or she is not supposed to see. The first instinct of many developers is to make the request an HTTP POST instead of a GET, as the value is not passed through the URL. The reality is that this technique is simply “security through obscurity.” Many web developer tools are available that allow an end user to view and manipulate post data or simply turn the POST into a GET. To address these concerns, APEX offers several new features that let developers easily protect their applications against such threats. Restricted Items In many scenarios, certain application- or page-level items should never be set by an end user. Suppose, for example, that the end user’s role, such as Administrator or Guest, is stored in an application-level item. If an end user can change the value of this item, she could gain access FIGURE 12-8 Primary Key Passed Through the URL Chapter 12: Secure Coding Practices in APEX 481 to pages or data to which she is not entitled. Each application or page item now has an attribute called Session State Protection. Setting this attribute to Restricted - May Not Be Set From Browser will prevent end users from tampering with the value of the attribute. The only way to change a Restricted item’s value is through constructs inside the application, such as computations or processes at the application or page level. This technique enables the developer to store values in items with the confidence that an end user cannot change their values. Checksum Completely blocking the ability to set an item from a URL is the most secure option and works well for application-level roles or attributes that are typically static for the session. However, in many scenarios, this technique simply won’t work, such as the “Report and Form on a Table” discussed earlier in this section. When a user clicks a row, we must have a way of determining which row was clicked to edit the proper row on the form page. The most common technique for this in APEX, as well as many other popular technologies, is to pass the value in the URL. Unfortunately, this gives the end user the opportunity to change the value. In response to this potential security threat, the concept of a URL checksum was built into APEX. When this feature is enabled, APEX uses a cryptographically strong Message Authentication Code or “MAC” to generate a checksum based on the parameters and their values in the URL. APEX then appends this checksum to the URL. This process occurs when APEX generates links to pages that require a checksum. When a link is clicked that sets the value of one or more items, APEX runs the items and values through the same function. Any change of a value in the URL will result in a different checksum when the request is received, thus allowing APEX to detect URL tampering. A great example of this is the Report and Form on a Table. Once we require a checksum for the ID item on the form page, APEX automatically generates the checksum for each link on the report page. Clicking a link works exactly as it did before, except you will now see a checksum appended to the URL. If you try to change the value of ID in the URL, APEX will simply return an error. If this checksum were a simple hash based on a well-known algorithm, it would be easy to spoof. However, since the algorithm also takes in a key or “salt” that is known only internally to the APEX engine, a nefarious user would need to determine the algorithm or algorithms used as well as the key. Suggested Session State Protection Scenario Session State Protection is extensively documented in the APEX Application Builder Users Guide. Many permutations of settings are possible for Session State Protection. Instead of dedicating a large portion of this chapter to all possible scenarios, I’ll provide some guidelines that cover the most common ones, which fall into two categories: items that should never be changed by a user, such as an application item storing the user’s role, and items that must be set through the URL; however, allowing the user to change item values is a security risk. Items That Should Never Change To ensure that the value of an item is never set by an end user using URL parameters, set the item-level Session State Protection attribute to Restricted - May Not Be Set From Browser. This is applicable to application- and page-level items. Sensitive Items Set Through the URL The scenario described earlier using the Report and Form example is a perfect candidate for URL checksums. To enable this feature, navigate to the Application Level Attributes | Security | Session State Protection Section, and click Page. Select the target page of a URL that requires a checksum, in this case the form page. Change the Page Access Protection attribute to Arguments Must Have Checksum. You must also set the session 482 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence state protection level for key items on the page, typically items that store the primary key of the row. Checksum Required - Session Level is the most secure setting. Application and User Level Checksums are used when sharing URLs or bookmarking is desirable. It is not necessary to require checksums for items that are not passed through the URL, as the values of those items will be overwritten by the process that returns the row into the page items. Figure 12-9 shows an APEX URL in which Session State Protection is enabled. The cs= parameter appended to the URL is the checksum. Password Items Items of type Password have always obscured the value from appearing on the screen so that someone watching over a user’s shoulder cannot read the password. However, password values are stored in the APEX session state table, which is accessible to anyone with a privileged database account. Any login page generated by APEX clears this session state as soon as the user logs in, but that value could persist in online redo log files or archive log files. It is also easy for a developer inadvertently to alter the process that clears session state for the login, leaving the password in the session state table. To address these situations, two new item types were introduced in APEX 3.2: Password (does not save state) and Password (submits when ENTER pressed, does not save state). Both item types insure that a user’s password is never written to a persistent store. Developers who upgrade applications or instances from previous versions of APEX to APEX 3.2 should verify that all password fields use these new item types. Encrypted Session State In addition to protecting passwords, a developer may want to protect other sensitive data from system administrators or anyone else who has a privileged account or access to the online redo or archive log files. Even if the data is stored in a table using programmatic or transparent encryption, any data element used in an APEX item is stored in the application session state table in clear text. Starting with APEX 3.2, developers can set an item-level attribute to store session state encrypted. To illustrate this point, the following example in Figure 12-10 sets the Store Value Encrypted In Session State attribute of the P11_SALARY item to Yes and leaves it set to No for the P11_EMAIL item. After submitting the page to make sure their values were stored in session state, I queried the WWV_FLOW_DATA table used to store APEX session state: APEX_030200@AOS> select item_name,item_value from wwv_flow_data where flow_instance = 3574272250559947 and flow_id = 107 and item_name in ('P11_EMAIL','P11_SALARY'); ITEM_NAME ITEM_VALUE P11_EMAIL JWHALEN P11_SALARY 948F90BDC554FBB74305B2AFA6E44102 FIGURE 12-9 Checksum added to URL Chapter 12: Secure Coding Practices in APEX 483 As you can see, P11_EMAIL is in clear text, while the value of P11_SALARY that was a four- digit number on screen is now stored in the session state table as an encrypted value. This value can be decrypted only internally by APEX and is thus protected from scenarios such as this. It’s very important to note that this setting affects how the data is stored only in APEX session state—it has nothing to do with how the value is stored in application tables. In this example, the value of the EMPLOYEES.SALARY column is not encrypted, only the value stored in the APEX item P11_ SALARY. So enabling encryption on this item does not encrypt data in the EMPLOYEES table. It is the developer’s responsibility to make sure that the application tables used to store sensitive data do so using technologies such as DBMS_CRYPTO or Transparent Data Encryption at the column or tablespace level. Leveraging Database Security Features One key benefit to the APEX architecture is that every database feature is available to APEX developers. In this section, we will explore the integration of VPD to implement row-level security. We’ll then leverage fine-grained auditing (FGA) to provide silent alarm for our most sensitive data. Both scenarios take advantage of the context information that APEX provides to better determine who the user is and where they are in a given application. FIGURE 12-10 Store Value Encrypted In Session State attribute . two-page APEX application that demonstrates the insecure and secure report column types and page item types. The following code, saved in a database table, simply writes a line of text onto. report output 480 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence A classic example of passing session state through the URL is the “Report and Form on a Table” generated. 474 Part IV: Applied Security for Oracle APEX and Oracle Business Intelligence Kochhar - 17000 De Haan - 17000 Hunold - 9000 Ernst

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

TỪ KHÓA LIÊN QUAN