A clear and obvious concern when implementing any type of security is performance. While VPD provides the best security protection—it’s consistent and constant—it is not magical. That is, the modified query will be executed and overall performance will be based on this final query string. One of the easiest ways to ensure high performing VPD is to create indexes on the predicate values. If your policy function returns “username = USER”, then an index on the USERNAME column will increase VPD execution. Bind VariablesBind variables help to ensure high performance by allowing the database to save valuable computing resources when queries differ only by variable values. The first area to investigate is the performance of the returned predicate. Because the actual SQL to be executed includes not only the original SQL, but also the SQL returned from the predicate, you have to ensure that this SQL string performs well. Bind variables are the staple of performance in an Oracle database. Bind variables allow the database to reuse SQL between database sessions; that is, the database can share a single parsed plan for multiple open cursors. The performance is achieved because the database doesn’t have to reparse the SQL. In some of the previous examples, the returned strings consisted of the SYS_CONTEXT function. This is critical because the policy function could have resolved the SYS_CONTEXT function and returned that string. The following will return “deptno = 20” for the SCOTT user: CREATE OR REPLACE FUNCTION dept_only ( This implementation is functionally equivalent to the one implemented before, but it is not equivalent from a performance perspective. Ensuring VPD performance comes from the fact that the SYS_CONTEXT is treated as a bind variable. If you do not use bind variables, but rather return the actual resolved value, for example, “deptno = 20”, the database will spend a lot of time reparsing the SQL statements. Performance as measured here is not based on how the SQL is generated. In the example, the VPD policy is invoked, and the predicate is produced. However, the application could have produced the same or similar SQL. The point is that it doesn’t matter how the SQL was generated—if you want to achieve stellar performance, you have to produce good SQL; bind variables are generally a good way to go. Code LocationAnother question on the design revolves around whether the SQL should be modified at the database or at the application. Essentially, from a performance perspective, it does not matter. The same process will have to occur regardless of where it occurs. That is, some procedural logic will fire, check some things, and then determine how to reform the SQL query, thus securing the data for the user. From a security perspective, the database implementation is much better. It guarantees that the SQL, and thus security, will always be enforced. This has value when the data may be needed by other applications and also helps provide defense in depth in the case that the web application is successfully attacked. In the latter case, the security of the application itself has been compromised, and it is only the database security that will now ensure that an attacker does not gain access to unauthorized data. Policy CachingAnother question arises on the performance regarding the time required for the database to invoke VPD—a.k.a. “overhead.” Because VPD invokes a function each time a statement or cursor is issued, performance can be a concern. To help ensure things are running extremely fast, the database allows you to cache the VPD policy. In Oracle 9i Database, this capability was introduced with a new STATIC_POLICY parameter. When set to TRUE while registering the policy with the DBMS_RLS.ADD_POLICY procedure, the database will cache, on the first execution of the VPD policy, the results from your policy function. This can result in significant performance improvements because the PL/SQL code implementing your VPD policy will not be called in further queries. You can still create a VPD policy and set the STATIC_POLICY parameter to true; however, that parameter is deprecated in Oracle Database 10g. The STATIC_POLICY was a good start, but Oracle realized there are still some enhancements that can be done. In Oracle Database 10g, the RLS package supports five new variations of policy caching. The replacement is a parameter called POLICY_TYPE, which allows you to set the caching to one of five different values:
You will see three examples of the caching: STATIC, SHARED_STATIC, and SHARED_ CONTEXT_SENSITIVE. You will not see DYNAMIC because that means no caching, and the CONTEXT_SENSITIVE caching is a subset of the SHARED_CONTEXT_SENSITIVE. STATIC Caching ExampleThe first caching example will use the STATIC option, which is equivalent to setting the STATIC_ POLICY parameter to TRUE in the Oracle 9i Database procedure. To test the caching, the policy function will be modified to incorporate an artificial latency. The DBMS_LOCK.SLEEP procedure simulates a policy function that takes two seconds to execute and will make the caching visible to you. The policy function owner will require execute privileges on the DBMS_LOCK package. Because the RLS will call this function, you can measure the execution time of your query to determine the latency this function causes. sec_mgr@KNOX10g> CREATE OR REPLACE FUNCTION user_only ( Recall this is the policy function guarding the SALARY column of the PEOPLE table. You can test the caching by querying the salaries from the table. The first query will be done prior to enabling the caching: scott@KNOX10g> SELECT username, salary FROM people It took four seconds, not two. The policy is invoked once during the SQL parse phase and once during the statement execution. You can alter the RLS policy to employ the use of the “static” caching for the column-sensitive policy previously defined for the SALARY column of the PEOPLE table: sec_mgr@KNOX10g> BEGIN Enabling the timing feature of SQL*Plus, you can see the benefit to using static caching. The first execution will invoke the policy, and the predicate will be stored in the Shared Global Area: scott@KNOX10g> SELECT username, salary FROM people The two seconds were introduced by PRED_FUNCTION. Any subsequent execution by any user will use the cached policy. To illustrate this, rerun the query. Because the cached predicate is stored in the SGA, the caching can be used for all user sessions across all schemas: scott@KNOX10g> SELECT username, salary FROM people While the policy will be cached for all users, the returned records are not necessarily the same. In the previous example, the policy always returns the same predicate. When the SYSTEM user executes the query, the policy is cached and different results are returned because the SYS_CONTEXT function returns a different user identity.
blog comments powered by Disqus |
|
|
|
|
|
|
|