Most people are familiar with databases, even if they don't understand how modern database management systems (DBMSs) work. My coursework at UMT has included several classes focused on databases: Database Design, Database Security, and Cloud Computing. The core topics covered in these courses are as follows:
Data inside a relational database is organized into tables. Tables are defined by the columns, or attributes, that they contain. For example, a table describing students may contain the following columns: student ID number, first name, last name, address, and phone number. Columns enforce constraints upon the data they contain by requiring that a uniform datatype is used. For example, the column corresponding to a student ID number may only accept integer values. Some column values may be NULL.
Entries within a relational database table are termed rows. An example row for the table described above could be: [345213, "John", "Harrington", "435 Ryman St. Missoula MT", 4062584752].
A primary key must not be NULL and is used to uniquely identify a specific row within a table. Multiple columns of a table may be combined to form a composite primary key. Every table in a relational database must contain a primary key.
A foreign key is a column in a table that references a primary key contained in another table. The datatype must be equivalent, but the column or attribute may have a different name in separate tables. Foreign key values may even be repeated within a column, meaning that they do not necessarily uniquely identify a record in the table in which they appear. Foreign keys form a crucial component of the relational model, as they allow a database designer to establish relationships between tables.
These topics are best illustrated with an example from a database I created for a course in Database Design.
id
.
id
.
guest_id
and
booking_id
.
Now let's look at how these tables were created, programmatically, using Structured Query Language (SQL):
create table booking(
id INT PRIMARY KEY AUTO_INCREMENT,
arrive DATE NOT NULL,
depart DATE NOT NULL,
special VARCHAR(60),
type VARCHAR(30),
event VARCHAR(30),
referral VARCHAR(30)
);
create table guests(
id INT AUTO_INCREMENT PRIMARY KEY,
fname VARCHAR(20) NOT NULL,
lname VARCHAR(20) NOT NULL,
dob DATE,
phone VARCHAR(18),
email VARCHAR(40),
age INT,
street VARCHAR(30),
city VARCHAR(20),
state VARCHAR(20),
country VARCHAR(20),
postal VARCHAR(10)
);
create table reservation(
guest_id INT,
booking_id INT,
occurred DATETIME NOT NULL,
status VARCHAR(20) NOT NULL,
bank VARCHAR (20),
acct VARCHAR(20),
PRIMARY KEY (guest_id, booking_id),
FOREIGN KEY (guest_id) REFERENCES guests (id),
FOREIGN KEY (booking_id) REFERENCES booking (id)
);
create table <TABLE NAME>
query and
described using the syntax
column name
datatype
additional specifiers
where
additional specifiers may
designate the column as a primary key, or that an integer value should automatically
increment.
guest_id
and booking_id
as a composite primary key, and defines these two columns as foreign keys and also
explicitly states
which table and column the values should reference.
The following image provides a high level overview of the database organization:
The following image describes how tables are related to one-another:
The following image clearly defines foreign-key to primary-key relationships:
CRUD is an acronym describing four common operations on any structured data (not necessarily databases, but any database management system should support these operations).
Next we will examine some CRUD operations performed using SQL on the project database, and get a better idea for how specific conditions can be provided with SQL commands in order to target these operations to specific data.
The code below creates an ACTIVITIES table used to store information about activities available at a Montana adventure resort:
create table activities(
name VARCHAR(30) PRIMARY KEY,
price DECIMAL(6, 2),
location VARCHAR(20)
);
Now that this table has been created, individual rows can be inserted:
insert into activities (name, price, location) values
('Whitewater Rafting', 700.00, 'Blackfoot River'),
('Trap Shooting', 450.00, 'East Range'),
('Archery', 300.00, 'Archery Range'),
('Horseback Riding', 500.00, 'Ovando'),
('Horseback Riding Overnight', 1500.00, 'Bob Marshall'),
('ATV Track', 400.00, 'ATV Track'),
('ATV Backcountry Tour', 2000.00, 'Ovando'),
('Cross Country Skiing', 200.00, 'Blast Park'),
('Snow Tubing', 200.00, 'Blast Park'),
('Canoeing', 300.00, 'Seely Lake'),
('Dog Sledding', 1200, 'Ovando'),
('Fitness Center', 30.00, 'Fitness Center'),
('Fly Fishing', 400.00, 'Blackfoot River'),
('Garnet Ghost Town Tour', 500.00, 'Garnet Ghost Town'),
('Hot Air Balooning', 7000.00, 'Launch Pad One');
Inserting data into a table is very straightforward; each row to be entered consists of a tuple describing attribute values for that row.
A simple read operation would consist of printing all rows for a given table. This
can be accomplished by using the command SELECT * FROM ACTIVITIES;
. The output is
shown below:
ACTIVITIES: +----------------------------+---------+-------------------+ | name | price | location | +----------------------------+---------+-------------------+ | Archery | 300.00 | Archery Range | | ATV Backcountry Tour | 2000.00 | Ovando | | ATV Track | 400.00 | ATV Track | | Canoeing | 300.00 | Seely Lake | | Cross Country Skiing | 200.00 | Blast Park | | Dog Sledding | 1200.00 | Ovando | | Fitness Center | 30.00 | Fitness Center | | Fly Fishing | 400.00 | Blackfoot River | | Garnet Ghost Town Tour | 500.00 | Garnet Ghost Town | | Horseback Riding | 500.00 | Ovando | | Horseback Riding Overnight | 1500.00 | Bob Marshall | | Hot Air Balooning | 7000.00 | Launch Pad One | | Snow Tubing | 200.00 | Blast Park | | Trap Shooting | 450.00 | East Range | | Whitewater Rafting | 700.00 | Blackfoot River | +----------------------------+---------+-------------------+
In order to update the price of Archery in the ACTIVITIES table, we would use the UPDATE command as follows:
UPDATE ACTIVITIES SET price = 500.0 WHERE name = "Archery";
The update can be verified by this time using a SELECT command with a condition:
SELECT * FROM ACTIVITIES WHERE name = "Archery";
This results in the following output:
ACTIVITIES: +----------------------------+---------+-------------------+ | name | price | location | +----------------------------+---------+-------------------+ | Archery | 500.00 | Archery Range | +----------------------------+---------+-------------------+
In order to remove a row from a table, we can use the DELETE command as follows:
DELETE FROM ACTIVITIES WHERE name = "Cross Country Skiing";
This results in the following change to the ACTIVITIES table:
ACTIVITIES: +----------------------------+---------+-------------------+ | name | price | location | +----------------------------+---------+-------------------+ | Archery | 300.00 | Archery Range | | ATV Backcountry Tour | 2000.00 | Ovando | | ATV Track | 400.00 | ATV Track | | Canoeing | 300.00 | Seely Lake | | Dog Sledding | 1200.00 | Ovando | | Fitness Center | 30.00 | Fitness Center | | Fly Fishing | 400.00 | Blackfoot River | | Garnet Ghost Town Tour | 500.00 | Garnet Ghost Town | | Horseback Riding | 500.00 | Ovando | | Horseback Riding Overnight | 1500.00 | Bob Marshall | | Hot Air Balooning | 7000.00 | Launch Pad One | | Snow Tubing | 200.00 | Blast Park | | Trap Shooting | 450.00 | East Range | | Whitewater Rafting | 700.00 | Blackfoot River | +----------------------------+---------+-------------------+
The queries demonstrated so far have been fairly basic. When implementing my project I found it necessary to use more advanced queries. Additionally, since the database was intended to be accessed via the web, I made use of PHP to interface the user-facing HTML/CSS/JS code with a back-end SQL database.
Before continuing it may be helpful to visit the link above and explore the functionality provided by the database implementation in order to better appreciate why the following commands have been written.
Also, note that the following PHP code is 100% vulnerable to SQL injection, a topic that will be addressed and resolved further down the page.
The PHP code below allows a reservation to be cancelled:
$booking = $_POST["booking"];
$check = "SELECT * FROM booking WHERE id = '$$booking'";
$check_result = mysqli_query($con, $check);
$check_numrows = mysqli_num_rows($check_result);
if ($check_numrows == 0) {
echo "The booking ID you entered does not exist";
}
else {
$update_reservation = "UPDATE reservation
SET reservation.status = 'cancelled'
WHERE reservation.booking_id = '$$booking'";
$update_activities = "UPDATE assign_activities SET status = 'cancelled'
WHERE assign_activities.id IN (SELECT guest_id
FROM reservation WHERE booking_id = '$$booking')";
$update_staff = "UPDATE assign_staff SET feedback = 'Reservation cancelled by guest'
WHERE booking_id = '$$booking'";
$delete = "DELETE FROM assign_lodging WHERE booking_id = '$booking'";
if (mysqli_query($con, $update_reservation)) {
echo "Reservation table updated
";
} else {
echo "ERROR updating table reservation ", mysqli_error($con);
}
if (mysqli_query($con, $update_activities)) {
echo "Activities table updated
";
} else {
echo "ERROR updating table assign_activities ", mysqli_error($con);
}
if (mysqli_query($con, $update_staff)) {
echo "Staff table updated
";
} else {
echo "ERROR updating table assign_staff ", mysqli_error($con);
}
if (mysqli_query($con, $delete)) {
echo "Lodging assignments cancelled
";
} else {
echo "ERROR cancelling lodging assignments", mysqli_error($con);
}
}
$booking
.
$booking
is stored in the variable $check
.
$update_reservation
query sets a reservation status to "cancelled" in
the
RESERVATION table
for the row corresponding to the booking ID.
$update_activities
query contains a nested query that is used to cancel
a
guest's activity registrations
if that guest is associated with the provided booking ID.
$update_staff
query is used to populate a table containing guest
feedback
of staff performance
with a note that the reservation was cancelled.
$delete
query is used to delete lodging assignments associated with the
provided booking ID.
The PHP code below is used to display feedback that bookings provided for staff members assigned to their stay:
$staff = $_POST["staff"];
$check = "SELECT fname, lname FROM staff WHERE id = '$staff'";
$check_result = mysqli_query($con, $check);
$numrows = mysqli_num_rows($check_result);
$staff_name_query = mysqli_fetch_array($check_result);
$staff_name = $staff_name_query['fname'];
$staff_last_name = $staff_name_query['lname'];
if ($numrows == 0) {
echo "Staff ID not found";
}
else {
$query = "SELECT booking.arrive AS Guest_Arrival,
booking.depart AS Guest_Depart, guests.fname AS Guest_First_Name, guests.lname AS Guest_Last_Name, assign_staff.feedback AS Feedback
FROM staff, booking, guests, assign_staff, reservation
WHERE staff.id = '$staff'
AND assign_staff.staff_id = staff.id
AND booking.id = assign_staff.booking_id
AND reservation.booking_id = booking.id
AND guests.id = reservation.guest_id";
if (mysqli_query($con, $query)) {
echo "
";
} else {
echo "ERROR Printing ", mysqli_error($con);
}
$result = mysqli_query($con, $query);
$num_relationships = mysqli_num_rows($result);
if ($num_relationships == 0) {
echo "No relationships found";
}
// show results of table with new data inserted
echo "All Guests Served By $staff_name $staff_last_name:
";
echo 'Note that feedback is provided by booking, not individual guests.';
echo "
\n";
echo "\t\n";
while ($fieldinfo = $result->fetch_field()) {
echo "\t\t$fieldinfo->name \n";
}
echo "\t \n";
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
echo "\t\n";
foreach ($row as $col_value) {
echo "\t\t$col_value \n";
}
echo "\t \n";
}
echo "
\n";
}
echo "
";
echo "
";
mysqli_free_result($result);
$staff
.
The following PHP code is used to display lodging history for a particular guest:
$guest = $_POST["guest"];
$check = "SELECT * FROM guests WHERE id = '$guest'";
$check_result = mysqli_query($con, $check);
$numrows = mysqli_num_rows($check_result);
if ($numrows == 0) {
echo "Guest ID not found";
}
else {
$query = "SELECT distinct guests.fname AS Guest_First_Name, guests.lname AS Guest_Last_Name, booking.arrive, booking.depart,
booking.type AS Type_Of_Stay, booking.event AS Special_Event,
assign_lodging.site_name AS Site, assign_lodging.lodging_number AS Number
FROM guests, booking, assign_lodging, reservation
WHERE guests.id = '$guest'
AND guests.id = assign_lodging.guest_id
AND guests.id = reservation.guest_id
AND booking.id = reservation.booking_id";
if (mysqli_query($con, $query)) {
echo "
";
} else {
echo "ERROR: ", mysqli_error($con);
}
$result = mysqli_query($con, $query);
$num_lodging = mysqli_num_rows($result);
if ($num_lodging == 0) {
echo "Guest does not have lodging history yet";
} else {
echo "
";
echo "
";
// show results of table with new data inserted
echo "All Guest Lodging History
";
echo "
\n";
echo "\t\n";
while ($fieldinfo = $result->fetch_field()) {
echo "\t\t$fieldinfo->name \n";
}
echo "\t \n";
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
echo "\t\n";
foreach ($row as $col_value) {
echo "\t\t$col_value \n";
}
echo "\t \n";
}
echo "
\n";
}
}
echo "
";
echo "
";
mysqli_free_result($result);
SELECT DISTINCT
query is used to remove duplicate values from the
columns
returned
by the query, ensuring that rows pertain to a unique guest lodging assignment, thereby
eliminating rows with
redundant values.
The following PHP code allows for a charge to be debited against a specified booking:
$booking = $_POST["booking"];
$billable = $_POST["billable"];
$occurred = $_POST["occurred"];
$charge = "INSERT INTO charge (booking_id, billable_id, occurred) VALUES ('$booking', '$billable', '$occurred')";
if (mysqli_query($con,$charge)){
echo "Charge Posted";
} else {
echo "ERROR Updating Table " , mysqli_error($con);
}
$show_charges = "SELECT * FROM charge WHERE booking_id = '$booking'";
$result_charge = mysqli_query($con, $show_charges);
echo "
";
echo "
";
// show results of table with new data inserted
echo "All Booking Charges
";
echo "
\n";
echo "\t\n";
while ($fieldinfo = $result_charge -> fetch_field()){
echo "\t\t$fieldinfo->name \n";
}
echo "\t \n";while ($row = mysqli_fetch_array($result_charge, MYSQLI_ASSOC)) {
echo "\t\n";
foreach ($row as $col_value) {
echo "\t\t$col_value \n";
}
echo "\t \n";
}
echo "
\n";
echo "
";
echo "
";
mysqli_free_result($result_charge);
The following PHP code allows a user to search for a reservation using multiple search criteria. Visit the form to try it out. This code is very similar to what has been shown above; however, the IN keyword is used to nest queries.
$fname = $_POST["fname"];
$lname = $_POST["lname"];
$guest = $_POST["guest"];
$phone = $_POST["phone"];
$email = $_POST["email"];
$booking = $_POST["booking"];
$search_reservation = "SELECT * FROM reservation WHERE guest_id = '$guest' OR booking_id = '$booking'";
if (mysqli_query($con,$search_reservation)){
echo "Searching Reservations Complete
";
} else {
echo "ERROR Searching " , mysqli_error($con);
}
$reservation_result = mysqli_query($con, $search_reservation);
$numrowsreservation = mysqli_num_rows($reservation_result);
$search_guest = "SELECT * FROM reservation WHERE guest_id IN (SELECT id FROM guests
WHERE fname = '$fname' OR lname = '$lname' OR phone = '$phone' OR email = '$email')";
if (mysqli_query($con,$search_guest)){
echo "Searching Guests Complete
";
} else {
echo "ERROR Searching " , mysqli_error($con);
}
$guest_result = mysqli_query($con, $search_guest);
$numrowsguest = mysqli_num_rows($guest_result);
echo "
";
echo "
";
if ($numrowsguest == 0 and $numrowsreservation == 0) {
echo "No guests or reservations found with information provided
";
}
else {
// show results of query
}
SQL injection is the process of passing SQL queries or commands as input. All of the forms
linked
earlier on this page to demonstrate
the database functionality accept input in order to perform some task. Expected usage of the
database
described on this page involves a resort employee
entering integer or string values for the purpose of creating, reading, updating, or deleting
information necessary to the normal operation of the resort.
A SQL injection attack leverages
these input forms in order to provide
SQL code instead of ordinary strings or integers that, if not escaped or handled properly, will
be
executed by the DBMS. Such commands
could have disastrous consequences;
for example, any of the form fields could be passed a string such as
DELETE * FROM RESERVATIONS
. The result would be the loss
of all records in the RESERVATIONS table. Additionally, according to the OWASP organization
, SQL injection attacks can be used read sensitive data, modify existing data, execute
administrative operations
on the database, and in some situations even issue commands to the operating system that the
DBMS is
running on top of.
For this project, PHP was used as an intermediary to link the front-end HTML forms (and the data they are capable of receiving) with the back-end DBMS. The PHP code is responsible for establishing a connection to the DBMS (from whatever server the PHP code is hosted on) and executing statements responsible for placing POST data in variables, and using these variables to perform operations (create and execute queries upon the DBMS). Since PHP is a commonly used language to bridge HTML form data and back end services, it should not be surprising that PHP contains methods of sanitizing, or escaping invalid input. Other languages such as Javascript have similar methods.
In this project, it is very straightforward to sanitize the input as it passes from the HTML
form
into the PHP code. PHP contains a method
mysqli_real_escape_string()
that accepts a string parameter. This method will
return a
sanitized string that will not
be able to execute any malicious action against the database. An example of how the previously
shown
PHP code used to search for a
reservation can be modified to mitigate SQL injection is below:
$fname = $_POST["fname"];
$lname = $_POST["lname"];
$guest = $_POST["guest"];
$phone = $_POST["phone"];
$email = $_POST["email"];
$booking = $_POST["booking"];
$sanitized_fname =
mysqli_real_escape_string($con, $fname);
$sanitized_lname =
mysqli_real_escape_string($con, $lname);
$sanitized_guest =
mysqli_real_escape_string($con, $guest);
$sanitized_phone =
mysqli_real_escape_string($con, $phone);
$sanitized_email =
mysqli_real_escape_string($con, $email);
$sanitized_booking =
mysqli_real_escape_string($con, $booking);
$search_reservation = "SELECT * FROM reservation WHERE guest_id = '$sanitized_guest' OR booking_id = '$sanitized_booking'";
if (mysqli_query($con,$search_reservation)){
echo "Searching Reservations Complete
";
} else {
echo "ERROR Searching " , mysqli_error($con);
}
$reservation_result = mysqli_query($con, $search_reservation);
$numrowsreservation = mysqli_num_rows($reservation_result);
$search_guest = "SELECT * FROM reservation WHERE guest_id IN (SELECT id FROM guests
WHERE fname = '$sanitized_fname' OR lname = '$sanitized_lname' OR phone = '$sanitized_phone' OR email = '$sanitized_email')";
That's it for the original project, completed for a course in Database Design. Be sure to visit the links below in order to visit the database portal and explore the project further. You are free to enter information into the database, but default data has already been entered. You can return to the default state of the database by using the Reset Database link on the Main Menu. Next, security enhancements discussed in a course on Database Security will be examined.
OracleDB is a DBMS that uses the MySQL (also owned by Oracle) engine but also includes some notable features attractive to large organizations intended to enhance security by implementing access control and by supporting hierarchical views according to a user's level of clearance. This is accomplished in several ways which will be discussed below:
create view charges as select booking_id, billable_id, occurred from charge;
charges
view will display the three columns of the CHARGE table along with
any data contained therein.
Why OracleDB? The course I took in Database Security was taught by an adjunct employed full time by the United States Department of Defense. I can only assume he has the greatest professional experience using OracleDB and prefers to base his course off of this DBMS. Alternatives exist, but they will not be discussed on this page.
The project outlined earlier on this page is a fully-implemented database intended to be used by a resort. Specifically, I designed this database in preparation for an internship with The Resort at Paws Up, located near Missoula, MT. While the course in database design imposed no security requirements whatsoever, it is worth noting that such a database would require extensive security measures considering that so many of this particular resort’s guests are well-known celebrities, musicians, actors, politicians, and other persons of interest to the general public. It is ostensible that such a database would be targeted not only by external attackers, but would also be exposed to a significant internal threat (rogue employees). For this reason, redaction, roles, views, and grants will play a central role in controlling which users can access what information.
Key users include employees with varied roles and, therefore, varying levels of access to data contained within the database. For instance, some office staff will be responsible for creating guest reservations and entering guest information into the database. Other staff will be responsible for reaching out to former guests to inquire about how satisfied they were with their experience, and also inform them of special events or promotions. Additional staff will be responsible for coordinating guest lodging and activity reservations. Certain staff will oversee the billing of guests and calculate all charges incurred against a booking. Additional staff will be responsible for supervising employees, assigning them to specific bookings, completing payroll, mailing out tax documents, etc.
The database can be divided into two main departments: one concerned with guests, and another concerned with employees. The department concerned with guests will contain tables to record information about guests (name, DOB, contact information, address, etc). Most of this information must be protected for obvious reasons (home address, phone number, birthday, etc.) Additionally, tables will be implemented to track guest booking information, reservation details, payment information, etc. and this information is likewise sensitive. Other guest details will not be considered sensitive, such as which lodging guests have been assigned to, which items guests have purchased, and what activities they have registered for.
The department concerned with staff will have privileges to view and modify (as appropriate) tables concerned with employees. Certain employee information regarding employee dependents will be protected. Staff assignments and general staff information will not be considered sensitive, as this could be needed by employees within the staff department for various reasons and does not present a security risk.
In OracleDB, one or more DBMS users will need to define roles, views, grants, and redaction. In the
code
samples below,
this user is named CIO
, and has full privileges across the DBMS. Additionally, four
levels
of clearance will be defined
in order to stratify DBMS access across a hierarchy of privilege:
The code snippets below illustrate how to accomplish this within OracleDB:
SQL> create user CIO identified by c; User created. SQL> grant create session to CIO; Grant succeeded. SQL> grant alter session to CIO; Grant succeeded. SQL> connect CIO/c; Connected.
CIO
is created and granted full privileges.
SQL> create role guest_classified; SQL> Role created. SQL> create role guest_secret; SQL> Role created. SQL> create role guest_top_secret; SQL> Role created. SQL> create role employee_unclassified; SQL> Role created. SQL> create role employee_classified; SQL> Role created. SQL> create role employee_secret; SQL> Role created. SQL> create role employee_top_secret; SQL> Role created.
SQL> grant select, update on activities, assign_activities, lodging, assign_lodging, billables, charge to guest_classified; SQL> Grant succeeded. SQL> grant select, update on activities, assign_activities, lodging, assign_lodging, billables, charge, booking to guest_secret; SQL> Grant succeeded. SQL> grant select, update on activities, assign_activities, lodging, assign_lodging, billables, charge, booking, guest, reservation, child to guest_top_secret; SQL> Grant succeeded. SQL> grant select on activities, lodging, role to employee_unclassified; SQL> Grant succeeded. SQL> grant select, update on activities, lodging, assign_activities, assign_lodging, billables, staff, role, assign_Staff, assign_role to employee_classified; SQL> Grant succeeded. SQL> grant select on charge to employee_classified, employee_secret, employee_top_secret; SQL> Grant succeeded. SQL> grant select, update on activities, lodging, assign_activities, assign_lodging, billables, staff, role, assign_staff, assign_role, dependent to employee_secret; SQL> Grant succeeded. SQL> grant select, update on activities, lodging, assign_activities, assign_lodging, billables, staff, role, assign_staff, assign_role, dependent, guest, child, booking, reservation, charge, to employee_top_secret;
SQL> create view guest_contact_info as select fname, lname, phone, email from guest; SQL> View created. SQL> create view guest_itinerary as select arrive, depart, special, type, event from booking; SQL> View created. SQL> create view guest_schedule as select id, name, scheduled, status from assign_activities; SQL> View created. SQL> create view guest_lodging as select guest_id, site_name, lodging_number from assign_lodging; SQL> View created. SQL> create view charges as select booking_id, billable_id, occurred from charge; SQL> View created. SQL> create view staff_roster as select fname, lname, dept, phone, email from staff; SQL> View created. SQL> create view staff_assignments as select role_name, staff_id, start, end from assign_role; SQL> View created. SQL> create view staff_guests as select staff_id, booking_id, feedback from assign_staff; SQL> View created.
SQL> grant select, update on guest_contact_info to guest_top_secret; SQL> Grant succeeded. SQL> grant select on guest_itinerary to guest_secret; SQL> Grant succeeded SQL> grant select, update on guest_schedule to guest_classified; SQL> Grant succeeded. SQL> grant select, update on guest_lodging to guest_classified; SQL> Grant succeeded. SQL> grant select, update on charges to guest_classified SQL> Grant succeeded. SQL> grant select on staff_roster to employee_unclassified, employee_classified, employee_secret, employee_top_Secret; SQL> Grant succeeded. SQL> grant select, update on staff_assignments to employee_classified, employee_secret, employee_top_secret; SQL> Grant succeeded. SQL> grant select, update on staff_guests to employee_classified, employee_secret, employee_top_secret; SQL> Grant succeeded
At this point, individual users (employees) can be created as appropriate and assigned the role that provides them with the least privileged access essential for performing their assigned tasks.
Next, data redaction methods specific to OracleDB will be explored:
SQL> begin 2 dbms_redact.add_policy ( 3 object_schema => 'CIO', 4 object_name => 'RESERVATION', 5 policy_name => 'PAYMENT', 6 column_name => 'ACCT', 7 function_type => DBMS_REDACT.REDACT_CCN16_F12, 8 expression => '1=1'); 9 end; 10 /
ACCT
column of the RESERVATION
table.
SQL> begin 2 dbms_redact.add_policy( 3 object_schema => 'CIO', 4 object_name => 'GUEST', 5 column_name => 'STREET', 6 policy_name => 'STREET', 7 function_type => DBMS_REDACT.RANDOM, 8 expression => '1=1'); 9 end; 10 /
STREET
column of the GUEST
table.
SQL> begin 2 dbms_redact.add_policy( 3 object_schema => 'CIO', 4 object_name => 'GUEST', 5 column_name => 'DOB', 6 policy_name => 'GUEST_DOB', 7 function_type => DBMS_REDACT.REDACT_DATE_MILLENNIUM, 8 expression => '1=1'); 9 end; 10 /
DOB
column of the GUEST
table.
SQL> begin 2 dbms_redact.add_policy( 3 object_schema => 'CIO', 4 object_name => 'GUEST', 5 column_name => 'PHONE', 6 policy_name => 'PHONE', 7 function_type => DBMS_REDACT.RANDOM, 8 expression => '1=1'); 9 end; 10 /
PHONE
column of the GUEST
table.
SQL> begin 2 dbms_redact.add_policy( 3 object_schema => 'CIO', 4 object_name => 'CHILD', 5 column_name => 'DOB', 6 policy_name => 'CHILD_DOB’, 7 function_type => DBMS_REDACT.REDACT_DATE_MILLENNIUM, 8 expression => '1=1'); 9 end; 10 /
DOB
column of the
CHILD
table.
SQL> begin 2 dbms_redact.add_policy( 3 object_schema => 'CIO', 4 object_name => 'DEPENDENT', 5 column_name => 'DOB', 6 policy_name => 'DEP_DOB’, 7 function_type => DBMS_REDACT.REDACT_DATE_MILLENNIUM, 8 expression => '1=1'); 9 end; 10 /
DOB
column of the
DEPENDENT table.
Additionally, this course in Database Security also required that a security plan and policy be implemented by the organization intended to use the DBMS:
Security Plan: As a resort catering to the rich and famous, we are aware that we have a huge crosshair placed upon the data we necessarily maintain regarding our guests and employees. As such, we will need to ensure that our internal network is segmented from the internet, and that services which must access the internet are located within a DMZ. Our IT department will routinely evaluate our network by conducting internal and external penetration tests in order to discover potential vulnerabilities so that they may be mitigated. All software and operating systems will be kept patched and up-to-date.
Security Policies:
Security Procedures:
An organizational security policy is inherently complex and requires the ability to adapt over time. The security policy for this resort is no exception. Ten different security engineers would likely have ten different implementations for this project. I have based my implementation upon Oracle documentation and the material which has been covered throughout the semester. While conducting additional research for this project, I found that such practices adhered to or closely resembled best practices suggested by industry experts such as the SANS Institute (see references below).
https://www.sciencedirect.com/topics/computer-science/principle-of-least-privilege
https://www.sans.org/information-security-policy
https://www.usf.edu/it/about-us/issp0000securityplan.pdf
https://www.bowiestate.edu/files/resources/information-security-public.pdf
https://www.sans.org/white-papers/34222/