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

Oracle Unleashed- P11

50 293 0
Tài liệu đã được kiểm tra trùng lặp

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Oracle Unleashed- P11
Trường học University of Example
Chuyên ngành Database Management
Thể loại tài liệu hướng dẫn
Năm xuất bản 2023
Thành phố Unknown
Định dạng
Số trang 50
Dung lượng 186,26 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

CREATE OR REPLACE TRIGGER indiv_timestamp BEFORE INSERT OR UPDATE ON individual FOR EACH ROW BEGIN :new.last_updt_user := user; :new.last_updt_date := sysdate; END indiv_timestamp; The

Trang 1

cause all references in the child table to be deleted automatically In this respect, using ON DELETE CASCADE is similar to creating a DELETE trigger on the referenced table This is an extremely powerful option and should be used with caution If it is not properly understood, unwanted automatic deletions could result

Although they are ideally suited to enforcing referential integrity, REFERENCES constraints may not be desirable in certain situations For example, if a table has a high volume of transactions and contains several foreign keys that are simple lookups, performance can be adversely affected by using the REFERENCES constraint Each time a row is inserted or updated, the referenced tables must be checked to ensure that each foreign key being inserted exists in the referenced tables Depending on the nature of the data and the importance of performance, it may be preferable to enforce the foreign keys through the application itself

Listing 20.10 This DDL script, containing a CHECK table constraint, is an improvement on the column constraint used in Listing 20.6.

CREATE TABLE individual (

CHECK (date_of_birth BETWEEN (TO_DATE('01JAN1845',

'DDMONYYYY', 'nls_date_language = American'))

AND last_updt_date)

Trang 2

uniqueness in the combination of individual_id and company_id It also implements the USING INDEX clause to designate a tablespace and storage specification for the index that will be created

Listing 20.11 This DDL script uses the ALTER TABLE syntax to create a UNIQUE table constraint and

a storage specification for the corresponding index.

ALTER TABLE ind_co_rel

ADD CONSTRAINT ind_co_rel_u UNIQUE(individual_id, company_id)

ALTER TABLE ind_co_rel

DROP CONSTRAINT ind_co_rel_u

/

ALTER TABLE ind_co_rel

DROP CONSTRAINT indco_ind_nn

/

ALTER TABLE ind_co_rel

DROP CONSTRAINT indco_co_nn

Trang 3

ALTER TABLE ind_co_rel

ADD CONSTRAINT ind_co_rel_pk PRIMARY KEY(individual_id, company_id)

Foreign key table constraints are implemented in much the same way as REFERENCING column constraints If

necessary, multiple columns can be included in a FOREIGN KEY table constraint This is not the case with the column constraint implementation Note also that the FOREIGN KEY keyword is only available for the table constraint syntax Listing 20.13, the final script for ind_co_rel, also defines temporary tables into which exceptions are logged

Listing 20.13 The final ind_co_rel script uses the FOREIGN KEY table constraint syntax and logs exceptions into temporary tables.

CREATE TABLE ind_co_rel (

individual_id NUMBER(10)

,company_id NUMBER(10)

,title VARCHAR2(80)

,last_updt_user VARCHAR2(20)

CONSTRAINT indco_lu_id NOT NULL

EXCEPTIONS INTO ind_co_err_1

,last_updt_date DATE

CONSTRAINT indco_lu_dt NOT NULL

EXCEPTIONS INTO ind_co_err_2

,CONSTRAINT indco_ind_fk FOREIGN KEY (individual_id)

REFERENCES individual(ID)

ON DELETE CASCADE

Trang 4

EXCEPTIONS INTO ind_co_err_3

,CONSTRAINT indco_co_fk FOREIGN KEY (company_id)

REFERENCES company(ID)

ON DELETE CASCADE

EXCEPTIONS INTO ind_co_err_4

,CONSTRAINT ind_co_rel_pk PRIMARY KEY(individual_id, company_id)

The EXCEPTIONS INTO clause is particularly useful in applications where frequent and timely bulk loads are required

In order to use SQL*Loader with the direct path option to maximize its performance, constraints must be disabled When the constraints are re-enabled, the EXCEPTIONS INTO clause can be used to categorize problem records by inserting them in separate tables based on the constraint that was violated This minimizes the negative impact constraints have on performance, while maintaining integrity and providing a means of identifying and resolving problems with the data being loaded

As shown by these examples, Oracle provides a wide variety of options for enforcing integrity through column and table constraints Constraints are powerful tools for enforcing integrity, but they should be used with care Overuse of

constraints can add significantly to long-term maintenance requirements, and misuse can create unwanted dependencies

or unnecessary exceptions The possible trade-offs involving constraints and performance will be discussed in greater detail later in this chapter

Trang 5

CREATE SEQUENCE individual_ids

START WITH 1

INCREMENT BY 1

NOMAXVALUE;

The values specified for the START WITH, and INCREMENT BY parameters in Listing 20.14 are the defaults

NOMAXVALUE is the default as well The script in Listing 20.13 will produce the same result as the following:

CREATE SEQUENCE individual_ids;

It is a good practice to explicitly declare these defaults for documentation purposes, if nothing else The implementation

is fairly self-explanatory The START WITH parameter indicates the first number that will be generated, INCREMENT

BY specifies a number to be added to the current value to generate the next value, and NOMAXVALUE indicates that there is no maximum to the numbers it will generate, (practically no maximum, although there is an upper limit)

The MINVALUE parameter is used only by descending sequences (Specifying a negative value for INCREMENT BY produces a descending sequence.) CYCLE, when used in conjunction with MAXVALUE or MINVALUE, indicates that the sequence should start from the beginning when the minimum or maximum value is reached The default for this option is NOCYCLE

The CACHE parameter indicates the number of values that should be pre-generated and cached by the sequence The default value for CACHE is 20 Raising this parameter can improve performance in high transaction volume

environments

ORDER ensures that sequences are used in the order generated Regardless of the setting of this option, the same value will never be returned twice If an application uses a sequence in a transaction that is rolled back, the value is simply discarded NORDER, the default for this option, is acceptable unless the sequence is being used like a timestamp to indicate the order of events over time

A sequence has two pseudocolumns, currval and nextval Currval returns the current value of the sequence, while nextval increments the sequence and returns the new value Listing 20.15 demonstrates how a sequence can be used in

an Oracle function to generate new keys when inserting records

Listing 20.15 This function accesses a sequence to fetch a new key when inserting a record.

CREATE OR REPLACE FUNCTION insert_indiv (last CHAR, first CHAR,

notes CHAR, dob DATE) RETURN NUMBER

IS

new_id NUMBER;

BEGIN

SELECT individual_ids.nextval INTO new_id FROM dual;

INSERT INTO individual VALUES (new_id, last, first, notes,

dob, user, sysdate);

Trang 6

It is a common practice to use sequences for generating unique primary keys One sequence can be used for many tables,

or a separate sequence can be created for each table requiring generated keys Either option is preferable to any key that requires user intervention, because typographical errors are bound to occur It is typically preferable to generate unique keys even when one exists naturally in the data (Social Security number, for example)

Using a sequence to generate primary keys can improve performance in certain situations, as well As mentioned

previously, integer joins are typically faster than character-based joins, and even when a natural integer primary key exists, a sequence is often a better choice To use Social Security number as an example, 10 bytes must be stored for each key If a sequence is used, starting with 1, a considerable amount of disk space can be conserved, and a much smaller index produced, which will result in less I/O Perhaps a less important consideration is the order in which values are inserted Depending on how inserts are handled by applications accessing the sequence, the index on a sequence-generated primary key may be created in ascending order naturally, which is somewhat of an optimization in terms of I/

O performance If the sequence is created with the ORDER option, and inserts are handled using Oracle subprograms

similar to Listing 20.15, this will always be true

Using Triggers

Triggers are stored procedures associated with a specific operation on a specific table A trigger is automatically fired when the operation with which it is associated is performed on the table with which it is associated Triggers can perform many of the same tasks as constraints, and in most cases, they can go beyond what constraints can do For example, a NOT NULL constraint can only ensure that a value is present in a column, but it does nothing to ensure the accuracy of

the data Listing 20.16 provides an example of how you can use triggers to enforce a NOT NULL constraint and ensure

the accuracy of the data being inserted

Listing 20.16 This trigger ensures that the columns last_updt_user and last_updt_date are inserted and updated accurately.

CREATE OR REPLACE TRIGGER indiv_timestamp

BEFORE INSERT OR UPDATE ON individual FOR EACH ROW

BEGIN

:new.last_updt_user := user;

:new.last_updt_date := sysdate;

END indiv_timestamp;

The simple trigger in Listing 20.16 ensures that the last_updt_user and last_updt_date are being inserted and updated

accurately in the individual table In effect, the trigger intercepts the actual values being inserted and replaces them with

Trang 7

user and sysdate Using the NOT NULL constraint for these columns is no longer necessary, and the trigger goes far beyond what the constraint could do

The trigger in Listing 20.16 also relieves the application of the burden of supplying values for the last_updt_user and last_updt_date columns when inserting and updating records

INSERT and UPDATE triggers are commonly used for customized transaction logging, or to generate statistical

summaries to be accessed by a different group of users than those applying the transactions For example, a large order

entry system might use an INSERT trigger to write only the date, the order amount, and the salesperson to a separate table to be used only for management reporting

The syntax for creating triggers is very similar to the creation of procedures, with a few notable exceptions The

BEFORE or AFTER keyword must follow the name of the trigger, indicating whether it should be fired before or after

the operation that causes it is fired

Although it may not seem logical to do so, this trigger had to be created with the BEFORE option Trying to implement this trigger with the AFTER option produces the following error:

ORA04091: table SCOTTY.INDIVIDUAL is mutating, trigger/function may not see it

Because the trigger is being executed by a process that is currently involved in a transaction on the same row, it cannot

be created with the AFTER option This would, in effect, invalidate the old correlation of the trigger

Immediately following the BEFORE or AFTER keyword is the action (or actions) with which the trigger is associated This can be INSERT, UPDATE, or DELETE, or any combination of these separated by OR The FOR EACH ROW keyword defines the behavior of the trigger when it is fired by statements affecting multiple rows The default behavior

is to fire the trigger only once, regardless of the number of rows affected A trigger may also include a WHEN clause, which limits the conditions under which it will fire

The WHEN clause can be used for specialized reporting, or to draw attention to a value that may seem to be out of range For example, an accounts payable system might use an INSERT trigger to log all payments of greater than

$10,000 to a temporary table, which can then be used to generate a report for management's review and approval This could be an alternative to a CHECK condition, which might prove to be overly restrictive In most circumstances, it would not be acceptable to reject a valid payment simply because it is unusually high On the other hand, management may be interested in reviewing or auditing these payments In this respect, a trigger can be used in a way that is

analogous to passively enforcing a CHECK constraint

Note that in Listing 20.16, the variable new is never declared This is the default correlation name associated with the new row (which is valid for inserts and updates only) The name old is associated with the old row by default, and is

valid for updates and deletes only These default names can be reassigned using a REFERENCING clause The

REFERENCING clause should placed immediately before the FOR EACH ROW keyword (if it is used), as in Listing 20.17

Listing 20.17 This trigger uses a REFERENCING clause to rename new.

CREATE OR REPLACE TRIGGER indiv_timestamp

Trang 8

BEFORE INSERT OR UPDATE ON individual

REFERENCING new AS new_row FOR EACH ROW

Listing 20.18 This trigger enforces the primary key on the individual table.

CREATE OR REPLACE TRIGGER indiv_get_key

BEFORE INSERT ON individual FOR EACH ROW

Listing 20.19 These triggers can be used to enforce several constraints on the individual table.

CREATE OR REPLACE TRIGGER indiv_ins_trg

BEFORE INSERT ON individual FOR EACH ROW

Trang 9

'nls_date_language = American'))

OR (:new.date_of_birth > sysdate)) THEN

RAISE_APPLICATION_ERROR(20001, 'Invalid birth date.');

CREATE OR REPLACE TRIGGER indiv_updt_trg

BEFORE UPDATE ON individual FOR EACH ROW

BEGIN

IF ((:new.date_of_birth < TO_DATE('01JAN1845',

'DDMONYYYY', 'nls_date_language = American'))

OR (:new.date_of_birth > sysdate)) THEN

RAISE_APPLICATION_ERROR(20001, 'Invalid birth date.');

In Listing 20.19, the PRIMARY KEY constraint is enforced for both inserts and updates The UPDATE trigger

completely prevents an ID from being changed, which might not be acceptable if this were not a generated key The triggers also enforce a CHECK constraint on date_of_birth and the NOT NULL constraints on last_updt_user and last_updt_date

Triggers can be used to enforce foreign key constraints, as well Refer to Listing 20.9 The REFERENCES constraints in

the example both contained the ON DELETE CASCADE option If the foreign keys integrity constraints are enforced by

the triggers in Listing 20.20, the REFERENCES column constraints could be removed

Listing 20.20 These triggers can be used to enforce foreign key constraints.

Trang 10

CREATE OR REPLACE TRIGGER indiv_del_trg

BEFORE DELETE ON individual FOR EACH ROW

BEGIN

DELETE FROM ind_co_rel WHERE individual_id = :old.id;

END indiv_del_trg;

CREATE OR REPLACE TRIGGER co_del_trg

BEFORE DELETE ON company FOR EACH ROW

BEGIN

DELETE FROM ind_co_rel WHERE company_id = :old.id;

END co_del_trg;

CREATE OR REPLACE TRIGGER ind_co_trg

BEFORE INSERT OR UPDATE ON ind_co_rel FOR EACH ROW

DECLARE

co_id NUMBER;

indiv_id NUMBER;

BEGIN

SELECT ID INTO co_id FROM company WHERE ID = :new.company_id;

SELECT ID INTO indiv_id FROM individual

WHERE ID = :new.individual_id;

EXCEPTION

WHEN OTHERS THEN

RAISE_APPLICATION_ERROR(20002, 'Invalid id.');

END ind_co_trg;

As these examples demonstrate, triggers can be used to perform the same tasks as table and column constraints In many cases, it may be preferable to use triggers because they are likely to provide better performance This is particularly true

in distributed environments, where it may not be possible to enforce foreign key constraints at all

When designing triggers, you should pay special attention to cascading triggers Cascading occurs when a trigger on one

table causes a trigger on another table to be fired Codependencies, in particular, can be a problem

Note that in Listing 20.20, the individual and company tables both have DELETE triggers that delete corresponding rows from ind_co_rel For the sake of example, assume that ind_co_rel has a DELETE trigger that deletes corresponding

rows in address_rel and phone_rel, and that individual and company also include these deletions in their DELETE

Trang 11

triggers

This presents numerous integrity problems If a relationship between an individual and a company is deleted, records in

address_rel and phone_rel that are related to both should be deleted Also, if an individual or company is deleted

entirely, all address_rel and phone_rel records related to the specific individual or company should be deleted When an individual or company is deleted, the ind_co_rel record is deleted, which causes its trigger to be fired, resulting in deletions from the address_rel and phone_rel tables If these records are also to be deleted by the trigger that was

originally fired by the deletion of the individual or company, the mutating table problem described earlier will occur In this case, the ind_co_rel should probably not have a DELETE trigger at all Meaningless records in address_rel and phone_rel exist only until the corresponding individual or company is deleted This is just one example of how cascading triggers can produce unexpected results

Application and Performance Considerations

Regardless of how integrity is enforced in the database, the application must have knowledge of the constraints The application must be able to submit transaction statements in the proper order, and it must know how to respond to

exceptions resulting from integrity problems This point is best illustrated through the use of an example Assume that the application needs to perform a single transaction based on the objects created in Listing 20.21

Listing 20.21 These objects participate in a single transaction.

CREATE SEQUENCE individual_ids

Trang 12

CHECK (date_of_birth BETWEEN (TO_DATE('01JAN1845',

'DDMONYYYY', 'nls_date_language = American'))

CONSTRAINT co_name_u UNIQUE

CONSTRAINT co_name_nn NOT NULL

CONSTRAINT indco_lu_id NOT NULL

EXCEPTIONS INTO ind_co_err_1

,last_updt_date DATE

CONSTRAINT indco_lu_dt NOT NULL

Trang 13

EXCEPTIONS INTO ind_co_err_2

,CONSTRAINT indco_ind_fk FOREIGN KEY (individual_id)

REFERENCES individual(ID)

ON DELETE CASCADE

EXCEPTIONS INTO ind_co_err_3

,CONSTRAINT indco_co_fk FOREIGN KEY (company_id)

REFERENCES company(ID)

ON DELETE CASCADE

EXCEPTIONS INTO ind_co_err_4

,CONSTRAINT ind_co_rel_pk PRIMARY KEY(individual_id, company_id)

It would be useful if the application could insert an individual, a company, and a record relating the two in one

transaction The foreign key constraints on indiv_co_rel dictate that this record must be inserted last In designing a process to complete this transaction, you should also consider that the application will need to insert an individual and a company separately, as well Listing 20.22 provides three functions to accomplish these tasks

Listing 20.22 These three functions guarantee that integrity constraints are satisfied for INSERTS into the objects in Listing 20.21.

CREATE OR REPLACE FUNCTION insert_indiv (last CHAR, first CHAR,

notes CHAR, dob DATE)

Trang 14

IF ((LENGTH(RTRIM(last)) > 0) AND

(LENGTH(RTRIM(first)) > 0)) THEN

SELECT individual_ids.nextval INTO new_id FROM dual;

INSERT INTO individual VALUES (new_id, last, first,

notes, dob, user, sysdate);

SELECT company_ids.nextval INTO new_id FROM dual;

INSERT INTO company VALUES (new_id, name, notes, user,

sysdate);

RETURN(new_id);

ELSE

Trang 15

CREATE OR REPLACE FUNCTION insert_ind_co(last CHAR, first CHAR,

notes CHAR, dob DATE, co_name CHAR,

co_notes CHAR, title CHAR)

Trang 16

These functions illustrate the point that in some cases, it may be a good solution to allow the client application to enforce integrity Column and table constraints can be costly, especially foreign key constraints, which require an additional read In an environment with a high volume of transactions and users, these constraints can have a significant negative impact on performance, possibly resulting in unnecessary contention, snapshot problems, and other bottlenecks

When using the application itself to enforce referential integrity, you can run batch processes periodically to ensure that the application is enforcing integrity You can create temporary tables to store exceptions for further analysis and

resolution, and you can use simple SQL to identify problem records For example, you can use a statement like the one following to identify invalid references to individuals in the ind_co_rel table

SELECT * FROM ind_co_rel INTO temp_no_ind WHERE individual_id NOT IN

(SELECT ID FROM individual)

If the application is properly designed, batch processes should not identify exceptions and would need to be run very infrequently

Primary key constraints, on the other hand, typically improve performance, especially if they are defined as a single small column This constraint causes an index to be built, and primary key values are often stored as foreign keys in other tables In these cases, declaring the primary key usually results in faster joins

In general, however, constraints have a negative impact on overall performance Depending on the nature of the data, security considerations, and standards of acceptable performance, you can rely upon the application itself to enforce many of the required integrity constraints

Trang 17

Summary

Column constraints, table constraints, triggers, and PL/SQL are all useful in enforcing integrity, but each approach also has limitations The best way to combine these elements to enforce integrity depends entirely on the application Most designs use a combination of all of these methods and attempt to strike a balance between pure performance and the strict enforcement of integrity

Previous

Page TOC

Next Page Home

Trang 18

Previous

Page TOC

Next Page Home

● 21

❍ Application Security

■ Reasons for Using Application Security

■ Using Application-Specific Database Objects

■ Table-Driven Application Security

■ Application and Performance Considerations

There are several reasons why you should use application security in addition to database security These reasons are discussed in the following section This chapter also covers the use of application-specific database objects and table-driven user interfaces, as well as application and performance considerations relating to the use of application security

Reasons for Using Application Security

In general, application security is used to enhance and supplement database security However, it would be dangerous to rely only on application security because there is no guarantee that users will access the database only through a single application

Application security can enhance database security by further limiting access to database objects and by providing an additional layer of abstraction (hiding the details of available database objects) If you limit access to application-specific stored procedures and functions and create application-specific roles, you can hide objects based on the specific user or the role of the user accessing the system On the same basis, the application can limit access of specific columns or make specific columns read-only by using different views for different roles or users

In a typical database application, the interface enables the user to communicate with the database by using menus and forms related to business processes and objects rather than tables and columns This is a convenient layer that prevents users from having to know the names of the tables and columns being accessed

In many cases, information in the database is used to control the behavior of the interface, based on the role of the user System tables contain security information used by the application to drive what capabilities are available to the

interface Menu options and forms to which the user has privileges to access are made visible, while others are hidden

For example, if an application has an administration menu containing options specific to database administration

functions, the entire menu is hidden from users who do not have the administrator role Any forms relating to these specific functions are inaccessible as well This method of using application security is obviously preferable to providing

a homogenous interface that enables users to try to perform operations on tables to which they have no privileges If the application allowed the user to access a database object that they did not have privileges to, the resulting errors would

Trang 19

have to be trapped and displayed to the user, which can result in misunderstanding and frustration on the users' part Using the database to drive application security is also preferable to hard-coding rules into the client application Table-driven application security makes it easy to update a user's privileges without having to reprogram the application

Another reason for using application security relates to databases that are accessed by multiple applications In this case,

a single user might have multiple roles, of which only one applies to the specific application Use an Oracle table when there are different application roles that could apply For example, an order entry system might have three different roles: one for order entry, one for management reporting, and one for system administration A billing system and a accounts receivable system might share common tables and be used by many of the same users These users may have slightly different role definitions for each application A simple Oracle table containing a user ID and a corresponding role can

be used to determine the correct role to be used for the application at runtime The privileges of the appropriate role can then be used to limit the user's view of the database to the scope that was intended for the particular application

Using Application-Specific Database Objects

The distinction between application security and database security is sometimes blurred, as is the case when you use application-specific database objects As illustrated by the previous example, different applications often access a

common database When you create objects to be used only by a specific application, application-level security is

common Although the objects exist in the database and database security is used, if the object exists only to service a specific application, it is "owned" by the application The argument can be made that rights granted to the stored object fall under the category of application security

In the definition of overall systems security, the "base" objects, (clusters, tables, indexes, and sequences), and rights granted to these objects are categorized as database security issues Views, procedures, and functions are considered application-specific objects, and rights granted to them are categorized as application security issues

Typically, in large database environments the primary DBA will not be responsible for creating and maintaining all application-specific objects One possible way to handle security for a large database accessed by multiple applications

is to grant rights to sequences and views of the tables to lead developers or administrators who serve as DBAs for the individual applications To do this, use the WITH GRANT OPTION clause Listing 21.1 follows the example of the database shared by order entry and billing/accounts receivable applications It demonstrates how the WITH GRANT OPTION might be used on a subset of the database objects

Listing 21.1 This script grants limited rights to the common database objects.

/* SEQUENCE */

CREATE PUBLIC SYNONYM account_no FOR account_no;

CREATE OR REPLACE VIEW accounts AS

SELECT * FROM account;

CREATE PUBLIC SYNONYM accounts FOR accounts;

/* SEQUENCE */

CREATE PUBLIC SYNONYM order_no FOR order_no;

CREATE OR REPLACE VIEW orders AS

SELECT * FROM order_on_acct;

CREATE PUBLIC SYNONYM orders FOR orders;

Trang 20

/* BillingAR System DBA & rights */

GRANT CONNECT

,RESOURCE

,CREATE USER

,CREATE ROLE

,CREATE PUBLIC SYNONYM

TO bardba IDENTIFIED BY billing;

GRANT SELECT ON account_no TO bardba

WITH GRANT OPTION;

GRANT SELECT, INSERT, UPDATE ON accounts TO bardba

WITH GRANT OPTION;

GRANT SELECT ON orders TO bardba

WITH GRANT OPTION;

/* Order Entry System DBA & rights */

GRANT CONNECT

,RESOURCE

,CREATE USER

,CREATE ROLE

,CREATE PUBLIC SYNONYM

TO oedba IDENTIFIED BY entry;

GRANT SELECT ON order_no TO oedba

WITH GRANT OPTION;

GRANT SELECT, INSERT, UPDATE ON orders TO oedba

WITH GRANT OPTION;

GRANT SELECT ON accounts TO oedba

WITH GRANT OPTION;

According to the previously described model of security, the script in Listing 21.1 is where database security ends and application security begins; enforcement responsibilities are delegated to the administrators of the specific applications Note that public synonyms were created to hide the system ID of the DBA, and that limited rights were granted to each application "super-user." The bardba and oedba users will create application-specific objects, roles, and users, and grant rights based on the individual application—within the database security restrictions enforced by the DBA by the limited rights granted to them

Trang 21

Note that the bardba user received read-only access to the orders view, and that the oedba user received read-only access

to the accounts view, while neither user received the delete privilege to either view This will limit the objects they can create, as well as the rights that they can grant to additional roles and users For example, the bardba user will not be able

to create a procedure to insert records into orders, or grant the insert privilege on orders to other roles and users

Application-specific objects include procedures, functions, packages, and views

Stored procedures and functions are typically used to insert, update, and delete records In many cases, these

subprograms will operate only on views, and not on the underlying tables themselves This makes it easier for

administrators to change the underlying structures as needed, without affecting the applications that access them Views are also used to present separate tables as one logical business object or to limit access to specific columns

You should use procedures and functions to perform all transactions for several reasons One reason to use database subroutines is that they can be used to enforce integrity For example, if a sequence is used to generate unique primary key values for a particular table, encapsulating the insert into a procedure or function can ensure that the sequence is always used When user IDs or timestamps are being stored, the values for the user IDs and timestamps can be supplied from within the stored procedure or function as well This ensures the integrity of these values, simplifies transaction processing for the client-side application, and helps reduce the amount of data being passed between the client and the server

Using procedures and functions can also enhance database security By granting only EXECUTE privileges on

subprograms, the views and tables on which the subprograms operate remain unavailable This prevents users from accessing them through SQL*Plus or one of the many desktop database or reporting tools that might enable them to modify the subprograms

There are additional advantages to using packages An Oracle package encapsulates a group of variables, constants, cursors, and subprograms into a single logical unit This can greatly simplify the process of granting privileges, and improve overall performance When EXECUTE is granted on a package, the user receives the execute privilege for each subprogram contained in the package specification The entire package is loaded into memory when a packaged object is first referenced by the application, which reduces I/O and improves performance for subsequent calls to subprograms within the package

You should always use views to present result sets to the application As mentioned previously, using views can help insulate the application from structural changes to the underlying tables and limit access to specific columns Views can also simplify embedded SQL in the application by completely eliminating the need for joins If all joins are handled by the views, the application can treat the result set as if it were a single table This can also simplify the process of granting privileges For example, if a view is created that joins seven tables, the user need only have the SELECT privilege to the view, not the underlying seven tables The user will then be able to access the view If the join were accomplished within SQL embedded in the application, the user would need the SELECT privilege for each of the seven tables Through column aliasing, views can also present result sets in terms of business lingo rather than column names, which are often very different

Ideally, application-specific stored procedures and functions are used for all transactions and operate only on views, whereas all result sets are retrieved through application-specific views Such a configuration greatly enhances overall security and can completely insulate the client application from changes to the structure of the underlying tables The procedures, functions, and views can be used to present a consistent database interface, regardless of the underlying structures on which they operate By granting only EXECUTE on subprograms and SELECT on views, the users cannot perform any transactions or SELECTS from outside the application-specific objects to which these privileges are

granted Exclusive use of procedures, functions, and views places a layer of abstraction between the users and the database, hiding the actual implementations of the tables This is becoming an increasingly important security

consideration as users become more sophisticated and generic reporting tools become more powerful

Public synonyms are a method of making a database object available to all users of the database You can be use public synonyms to hide the ID of the owner of application objects and prevent an application from having to specify a schema

Trang 22

Granting privileges to the public synonyms rather than the objects themselves also provides an additional layer of abstraction The diagram in Figure 21.1 provides a visual representation of the model of application security that has been presented in this section

Figure 21.1 This diagram represents the role of database objects in application security

The application itself communicates with application-specific objects in the database through public synonyms Stored procedures and functions operating on views are used exclusively for transaction processing, and views are used to retrieve all result sets This method of communicating with the database provides the highest degree of abstraction and security and simplifies the process of developing the client application

Table-Driven Application Security

You can use information stored in Oracle tables to drive application security This solution is particularly useful when security restrictions are likely to change and flexibility is required As mentioned in the previous section, you can use a table in Oracle to determine the default application role of the current user The role can then be used as the basis for determining which menu options, forms, and controls are available to the user

First, you must construct a table to store the application role of each user This can be a simple two-column table made

up of the user ID and application role Each user should have only one role If a particular user should have access to more than one role, you should create a new role and grant the privileges of the required roles For example, if a user should have the privileges of the roles oe_user, oe_management, and oe_admin, a fourth role should be created as shown following:

CREATE ROLE oe_superuser;

GRANT oe_user, oe_management, oe_admin TO oe_superuser;

GRANT CONNECT, oe_superuser TO scotty IDENTIFIED BY tiger;

The user's role should be determined by the application immediately after the connection is established so that it can be used to enable, disable, or hide menu options as needed The code that will alter the main window's menu should be placed in the window's constructor so that all changes are made before the window is instantiated This will prevent the hidden options from being momentarily visible, before the menu is repainted One possible table definition for

controlling menu behavior appears in Listing 21.2

Listing 21.2 One possible way to store application security information related to menus.

CREATE TABLE oe_menu_privileges (

app_role VARCHAR2(20)

,menu_item_id VARCHAR2(10)

,visible NUMBER(1) NOT NULL

,enabled NUMBER(1) NOT NULL

,CONSTRAINT menu_priv_pk PRIMARY KEY (app_role, menu_item_id)

);

Defining the menu item identifier as a numeric value might be preferable to a character data type, depending on the tool

Trang 23

you used to develop the client application Many popular Windows development tools provide the Tag property as the only possible way to identify a particular control at runtime (besides the actual text of the menu item) This property is typically a string data type and should be stored as such in the database Be careful to prevent trailing spaces from being stored in this column Trailing spaces are easily overlooked, and might cause comparison problems

The visible and enabled columns in Listing 21.2 should contain the numeric representations of the boolean values TRUE and FALSE so that they can be used to set the corresponding properties directly For example, a Delphi application might use a method like the following one to directly enable or disable a menu option from a TTable object:

mnuAdmin.Enabled := tblMenuSecurity.FieldByName("ENABLED").AsBoolean;

One difficulty in dynamically altering menu options based on tabled information is in determining which menu option is referenced in the table Depending on the tool being used, a menu item can be identified by an integer ID or by a string value assigned to the Tag property Regardless of the means by which a menu option is identified, the application must

be able to iterate through menu options to find a match for a menu ID read from the database In some cases, the only available means of accomplishing this is to provide a switch statement, with a separate case for each possible menu item identifier Consider this when you design menu security If only a few items will be disabled or hidden for any given role, the number of items that must be checked against values read from the database will be minimized This, in turn, will make the code required to accomplish these tasks smaller and easier to maintain Listing 21.3 presents a sample implementation of these concepts in Visual Basic

Listing 21.3 This Visual Basic subroutine uses a control array to alter a form's menu at runtime.

Sub SetMenuOptions(dsMenuOptions() As Dynaset)

Trang 24

values read from the database However, this approach has its limitations A menu control array can contain options only

at the same level Also, when controls are part of an array in Visual Basic, they share the same event code Each event receives the index of the array to which the event currently applies as a parameter This requires additional logic in event handlers for control arrays

Many development tools do not provide control arrays as an option, so the code to match a menu item with a database value becomes more application-specific The problem inherent to this method of using tables to control menu options is that the hard-coded menu identifiers must exactly match the values stored for them in the database A change to either the identifier within the client application or to the value of the identifier in the table will cause this means of enforcing application security to fail In most cases, if a menu option can possibly be disabled by the application security

mechanism, it should be disabled by default This is based on the assumption that if there are problems in properly matching values from the database, erring on the side of increased security is usually better

Maintaining application security for menu options can be simplified by the design of the menus Options that can

potentially be disabled or hidden should be top-level menu items, and where groups of options can be disabled, they should be grouped together under the same top-level menu item wherever possible Limiting the number of items that will need to be stored in the database and checked at runtime will improve performance and limit the possible points of failure

Using the previously described order entry subsystem as an example, assume that only users with the role oe_admin will have access to update and insert records into lookup tables and to add new users to the system These two operations can

be logically grouped into a top-level menu category, Admin Using this design, the application need only set the state for the top-level menu item The Admin menu option should probably be made invisible (rather than disabled) for users who

do not have access to it, because the options it contains will not be available to these users under any circumstances Figures 21.2 and 21.3 show examples of what the main application window might look like to oe_admin and non-oe_admin users, respectively

Figure 21.2 This main window has all top-level menus visible and enabled

Figure 21.3 In this main window, the top-level menu item Admin is completely hidden from a user who does not have the oe_admin role

In some cases, it might be necessary to enable access to a subset of options in a drop-down menu For example, a second role, oe_manager, might have privileges to add a new user, but not to modify lookup tables For this user, the

application's main menu can appear as in Figure 21.4

Figure 21.4 In this main window, the menu option Look-Ups is disabled for a user who has the oe_manager role

Whether you make menu options invisible or disabled is a matter of design preference In most cases, it makes more sense to completely hide an option that is unavailable to the current user Simply disabling a menu option implies that there are circumstances under which it will be enabled However, when the menu option is part of a drop-down, making

it invisible can leave only a single option, which is inconsistent with the standard uses of drop-down menus Regardless

of the way you enforce application security for menus, you should apply it consistently throughout the application

You can apply similar methods and principles to enforce application security for windows and specific controls In some cases, disabling or hiding a menu option prevents access to a particular form Under these circumstances, no additional security should be required to prevent a user from accessing the form However, it is more common for a particular form

to be read-only for a specific application role or group of roles In some cases, specific controls must be made read-only

or disabled based on the role of the user

As with menu options, you can design tables to drive application security for access to forms and specific controls

Trang 25

Listing 21.4 demonstrates one possible implementation of data-driven window and control-based application security

Listing 21.4 This DDL script creates tables that can be used to dynamically alter the states of windows and controls at runtime.

CREATE TABLE oe_window_privileges (

app_role VARCHAR2(20)

,window_id VARCHAR2(10)

,read_only NUMBER(1) NOT NULL

,CONSTRAINT window_priv_pk PRIMARY KEY (app_role, window_id)

,visible NUMBER(1) NOT NULL

,read_only NUMBER(1) NOT NULL

,CONSTRAINT cntrl_priv_pk PRIMARY KEY

(app_role, window_id, control_id)

);

The same potential problems that apply to data-driven menu security apply to data-driven window and control security First, there must be a method of determining the application role for a specific user If application security is being applied to menu options, the same application role should apply to window and control-based security for a specific user The user's role would then need to be read only once and stored in a global variable to be used whenever security

restrictions must be checked Within the table being used to determine which windows and controls can be accessed for a particular role, there must be a way to uniquely identify a window as well as individual controls within a window Again, the problem with this approach is that the identifiers must exactly match those being used by the client application As is the case with menu options, many development tools have only a Tag property available to use as this identifier Any mismatch between identifiers in the application and the identifiers being stored in the table will result in a breakdown of application security

Code used to retrieve security information from the database and alter the states for windows and controls should be placed in the appropriate constructors Depending on the development tool, this can be a potential problem because objects that need to be referenced might not be instantiated at the time the window is constructed For example, in C or C++, the constructors for a window's controls are typically called from within the constructor of the window itself The application should retrieve values from the database before calling the constructors for any controls that might be

affected by application security The controls themselves can then be disabled or hidden as needed

In MFC applications, for example, the Create member function is used to position and set the style for most interface objects An application can set the style constants dynamically at runtime by calling Create with style constants read from the database For example, in Windows 3.1, the ES_READONLY style constant can be passed to the Create

Ngày đăng: 28/10/2013, 23:15

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN