The
Need for Secure Data
Robert Bernier
All is not well for companies specializing in data management;
they are under increasing pressure to ensure the security of personal
information. As a result of recent events, there's a movement
among many governments to enact new, tough privacy legislation.
When these laws take effect (and they are already active in many
jurisdictions), they will force companies who collect personal information
to be liable if the security of their data-warehouse is breached.
Recall the ChoicePoint incident that exposed hundreds of thousands
of social security numbers in late 2004.
The legislation that is currently being proposed in California,
for example, describes not only who and under what conditions confidential
information can be released but also how that information should
be stored on the servers. Suppose a hard drive is stolen, or more
likely sold off, that contains driver license numbers, credit card
numbers, etc. The law requires that those people to whom the information
belongs must be informed by the company that compiled that information.
The enterprise is held liable for all subsequent issues that may
arise from the loss of control of that data. However, if the data
has been encrypted, then it is not necessary to inform those individuals
because the information cannot be harvested by criminal elements.
The purpose of this article is to introduce a technique that addresses
this new climate of security threats and the expectations from both
government and public alike. This method is easy and effective.
It will work even if you lose control of the hardware. The technology
is called "file system encryption", and the tool set is
common to all Unix-like operating systems.
The Technical Nitty Gritty
No special hardware requirements are necessary and any relatively
recent distribution of your operating system will work (e.g., Linux,
FreeBSD, Solaris, even OSX).
For the purposes of this article, all utilities and methods will
be made in the context of a Debian-based distribution of Linux using
a 2.6 series kernel. Note that Microsoft-oriented people, who have
very little experience with Linux, can still take advantage of this
article by downloading the latest version of "pg_live",
a Linux live CD that includes a replication-enhanced version of
PostgreSQL 8.0. All you need to do is put it in the PC and turn
it on. Pg_live will boot up and self-configure itself to run on
your machine. It doesn't install on the hard drive and runs
exclusively in RAM. Pg_live is available through Bit Torrent and
is also available for download at the SRA America site at:
http://sraapowergres.com
You can learn more about pg_live and how to use it at:
http://sraapowergres.com/en/newsletter/issue_02/
Creating and Using a Simple File System
Creating a file system will require the following utilities: dd,
losetup, mount, and mkfs.
The first step is to create an empty file that will hold the file
system. You will want to consider how large you want it to be; otherwise,
if it's too small, you will need to resize it later.
Creating a file is accomplished using the utility dd, you
don't need to be root to do this. The following command will
create a 100-KB empty file made up of the null character:
dd if=/dev/zero of=~/tmp/mysystemfile bs=1k count=100
The "if" switch identifies the input source (/dev/zero)
and the "of" switch identifies the name of the output file
(mysystemfile).
The "bs" switch defines how many BYTES should be read
and inputted into the file at a time. Note that in this example
the letter "k" was added to the number "1";
this means that a block of 1,024 bytes is inputted and outputted
to the file "mysystemfile". The letter defines the unit
of measure (i.e., "b" for bytes, "k" for kilobytes,
"M" for megabytes, and "G" for gigabytes).
The count switch defines the number of reads and writes that should
take place (i.e., bs=1k and count=100 means 1,000 X 100 or 100 KB).
Avoid making the bs value too large, such as the following, when
attempting to create large systems files (e.g., 10 gigabytes):
dd if=/dev/zero of=~/tmp/mysystemfile bs=1G count=10
This command fails if you don't have at least 1 GB of RAM (1.024
GB to be exact). Use a higher count number instead. The following
is more reasonable because it inputs/outputs smaller, 1 MB (1.024
MB), chunks:
dd if=/dev/zero of=~/tmp/mysystemfile bs=1M count=10000
Once created, the next step is to associate this file to a loop device
using the losetup utility. There are eight loop devices on
my own system, the first one being loop0. You'll have to have
root privileges to do this:
losetup /dev/loop0 /home/bernier/tmp/mysystemfile
It's time to format the file system, which is accomplished using
the standard mkfs utilities. For maximum security DO NOT create
a journaled file system such as ext3. Use something like ext2, otherwise
you'll have sensitive information in the cache memory:
mkfs /dev/loop0
Loop0 is, of course, where "mysystemfile" has been associated
as the device.
Mounting the device is accomplished by using mount as root:
mkdir /home/bernier/mnt
mount -t ext2 /dev/loop0 /home/bernier/mnt
Note that, in most situations, the mount command will recognize
the file system automatically, therefore the -t switch is not
really necessary under Linux.
Typing mount without using switches returns a listing of
all the devices currently mounted.
You can unmount the device with the umount command. Remember
not to have any process running inside the file system or you won't
be able to unmount it:
umount /home/bernier/mnt
Detaching the file "myfilesystem" from the device loop is
the last step and is accomplished using the detach switch -d
in the losetup command:
losetup -d /dev/loop0
Now that a file system has been created in "mysystemfile",
future mounts and unmounts can be accomplished with a single command:
mount -o loop /home/bernier/tmp/mysystemfile /home/bernier/mnt
Using Encryption in a File System
The encrypted file system is first created, using losetup.
The Debian distribution on which I based this article provides a
number of different ways to accomplish this. The "loop-aes"
package, used in this case, replaces the distribution's default
mount, umount, and losetup utilities with encryption-enabled
versions. But you must first have the crypto libraries compiled
into the machine's kernel.
The type of encryption utilities and libraries available to you
largely depends on what part of the world you're located in.
Assuming you are downloading from a local Debian server in North
America, the install command for the correct packages are:
apt-get install loop-aes
The losetup utility, as demonstrated below, requires that you
manually input a password. Some ciphers such as "aes" require
a minimum of 20 characters in length; otherwise the command fails
and you get an error message.
losetup -e aes /dev /loop0 /home/bernier/mysystemfile
password: XXXX..
mkfs /dev/loop0
mount /dev/loop /home/bernier/mnt
Verify that the file system is active by typing mount without
any options. You can also identify the particular encryption composing
losetup -a, which lists all currently configured loop devices.
Once you have created your encrypted file system, you can remount
it with a single mount command using the -o option
switch:
mount -o loop,encryption=aes /home/bernier/tmp/mysystemfile \
/home/bernier/mnt
Choosing Your Password
Using the -p0 switch allows for standard input of the password.
This lends itself well to a script, thus making the exercise of
typing out a long password less painful:
cat mypasswordFile.txt | losetup -e aes -P 0 /dev/loop0
/home/bernier/mysystemfile
The truly security-minded individual can generate a password of any
length and save it to a file on a removable device, such as a floppy
disk (or even an iPod). This two-line example uses "openssl"
to generate 6,000 ASCII characters and saves it as a password file.
It is then piped as standard input to "losetup":
openssl rand -out mypasswordFile.txt -base64 6000
cat mypasswordFile.txt | losetup -e aes -p0 /dev/loop0
/home/bernier/tmp/mysystemfile
About Permissions
The last step is to create directories in the encrypted file system
for the use of users and applications. In this example, I'm
creating a "bernier" account for myself so that I can
write data into the encrypted file system once it's mounted:
mkdir /home/bernier/mnt/bernier
chown bernier.bernier /home/bernier/mnt/bernier
Mounting the Encrypted File System
Mounting an encrypted file system requires root privileges; however,
there are a number of techniques that can be used that will permit
an ordinary user this same ability. The method shown here modifies
the fstab file, which provides static information about the file
systems, located in the etc directory. Add the following line:
/home/bernier/tmp/mysystemfile /home/bernier/mnt ext2
defaults,user,noauto,loop,encryption=aes 0 0
Here's what the above line says -- the first field is the
file containing the encrypted file system. The second field is the
mount point. The third field is the file system type. The fourth field
consists of a comma-separated list of options that apply to the mount
and losetup commands, respectively. The fifth and sixth options
relate to the dump and fsck commands, respectively;
you can leave them both at "0".
Note that the options in the fourth field are read left to right.
Options declared on the left are altered by subsequent commands
to the right. The "noauto" option prevents the file system
from automatically being loaded at boot time. Refer to the mount
man page for further information about these and other options you
can use here.
User name "bernier" can now mount the encrypted file
system with the following command:
cat mypasswordFile.bin | mount -p0 /home/bernier/mnt
The password option "p0" was intentionally left out of the
fstab file because it deprives a potential cracker of important information
as to how and where the password is coming from.
There still might be problems with the way the fstab entry has
been made if one considers that the "user" option permits
anybody to attempt to mount the file system. Even though the attempt
would require a password, this setup could lend itself to a brute
force attack. At the very least, it could lead to unmounting problems
if another user succeeded in mounting it. The issue can be resolved
by doing two things:
1. Change the "fstab" option from "user" to
"nouser" such that only root can invoke this mount instruction.
2. Create a "sudo" entry permitting user account "bernier"
the ability to mount the file system.
Therefore, the "fstab" entry can be rewritten as:
/home/bernier/tmp/mysystemfile /home/bernier/mnt ext2
defaults,nouser,noauto,loop,encryption=aes 0 0
These entries to the sudoers file permit user name "bernier"
the ability to mount the file system via the sudo command:
Cmnd_Alias MOUNT_ENCRYPT = /bin/mount -p0 /home/bernier/mnt
Cmnd_Alias UMOUNT_ENCRYPT = /bin/umount /home/bernier/mnt
bernier ALL = MOUNT_ENCRYPT, UMOUNT_ENCRYPT
The mount and umount commands can now be used by user
name "bernier":
cat mypasswordFile.bin | sudo mount -p0 /home/robert/mnt
sudo umount /home/robert/mnt
A Word about Encryption Ciphers
Choosing what to use from the available ciphers depends upon two
factors: security and speed. The more secure the data, the slower
the processing. The fastest cipher is XOR encryption, but this isn't
really much of a cipher because it is an obfuscation technique.
On the other hand, AES256 is extremely secure with a 256-bit encryption
algorithm, and the password is hashed with SHA-512. The security
of a number of the ciphers offered depends on the length of the
password. Hence, the longer the password the longer the encryption
key length and, of course, the harder it becomes to crack the password
using a brute force method.
Note that Debian's mount utility, in the aes package,
can use gpg public key encryption (asymmetric ciphers). However,
for the purposes of keeping this article from turning into a book,
I will refrain from discussing this form of encryption and concentrate
rather on the symmetric ciphers.
Being Practical
There are two areas of usage where you can put encrypted file
systems to good use -- the first is a laptop that carries sensitive
data. The second is a database server that holds sensitive information,
such as credit card numbers.
The Laptop
The only thing that I'd like to add here is that a good login
script streamlines the mount process for the user account. As a
further security measure, you might want to execute the mount command
from a shell that doesn't record the keystrokes (i.e., beware
of bash's history functionality).
Securing Sensitive Data on a PostgreSQL Database Server
While you can perform row-wise encryption in a PostgreSQL database
with the existing modules in the PostgreSQL distribution, column-wise
and even table-wise encryption is possible when using the 8.0 table
partitioning feature and storing data in an encrypted file system.
The method outlined here involves creating an updatable view that
performs INSERTions and SELECTs. The columns are located not only
in two separate tables but in two different partitions where one
is in the clear/unencrypted (the name of the credit card holder)
and the other is encrypted (the credit card number itself). Keep
in mind that you want to keep as little information as possible
in an encrypted format otherwise your installation is going to suffer
a performance hit.
The following instructions assume that you have Postgres 8.0 already
running and that the data cluster is located in the directory "/var/lib/pgsql8".
Carry out the following instructions in a console as "root":
cd /var/lib/pgsql8
mkdir mnt
dd if=/dev/zero of=encryptedPartition bs=1M count=30
openssl rand -out mypasswordFile.txt -base64 60
cat mypasswordFile.txt | losetup -p0 -e aes256 /dev/loop1 \
encryptedPartition
mkfs /dev/loop1
mount /dev/loop1 mnt
mkdir mnt/data
chown postgres.postgres mnt/data
You will have noticed that I created a 60-character randomly generated
password using "openssl". It's quite easy creating
passwords of any length using the openssl command-line utility from
the OpenSSL cryptography toolkit.
These SQL commands are executed from the "psql" client
as the superuser "postgres":
psql -Upostgres template1
CREATE DATABASE client;
\c client
CREATE TABLE client(id serial,name text);
CREATE TABLESPACE encrypted LOCATION '/var/lib/pgsql8/mnt/data';
CREATE TABLE confidential(id serial,credit_card text) \
TABLESPACE encrypted;
Here's a little bit of PostgreSQL magic. The two tables "client"
and "confidential" can be queried as one table by combining
them into a view called "v_client":
CREATE OR REPLACE VIEW v_client (name,credit_card)
AS SELECT name,credit_card
FROM client,confidential
WHERE client.id=confidential.id;
The following "rewrite rule" creates an updatedable view
that permits data to be inserted transparently to both tables as though
they were one:
CREATE OR REPLACE RULE ruleInsert_v_client AS ON INSERT
TO v_client DO INSTEAD
(
INSERT INTO client (name) VALUES (NEW.name);
INSERT INTO confidential (credit_card) VALUES (NEW.credit_card)
);
The special table name NEW (i.e., NEW.name, NEW.credit_card) refers
to values that are being inserted or updated into a table. The table
name OLD can also be used in a rewrite rule when the commands <code>UPDATE<text>
or <code>DELETE<text> are used. Please refer to the PostgreSQL
reference section under SQL COMMANDS for more information on rewrite
rules.
The last series of steps involves testing what you've created
by INSERTING and performing SELECT queries. Now we test... and it
works:
INSERT INTO v_client(name,credit_card) \
VALUES('Robert Bernier','23412441');
INSERT INTO v_client(name,credit_card) \
VALUES('Brian Killer Pat','22345599');
INSERT INTO v_client(name,credit_card) \
VALUES('Rocky Romantic','97274375');
SELECT * FROM v_client;
Tips
At file system creation time, you can prevent typing mistakes
by using the -P switch in the losetup command so that
it asks for your password twice:
losetup -P -e aes /dev /loop0 /home/bernier/mysystemfile
Practice everything covered here using xor encryption because it's
very fast and doesn't require very long passwords, enabling you
to type it out by hand.
Experiment with different encryption algorithms as you create
your file system. Their performance will vary according to your
security needs as well as your hardware configuration. Remember,
you can only use those ciphers that have already been encrypted
into your kernel.
Studying the man pages, listed at the end of this article, will
offer you many options to increasing file system security.
Consider keeping your password file physically separate from your
server/laptop in order to make it much more difficult to gain unauthorized
access to the file system.
Make sure that you either manually unmount or install a script
that will do it whenever you shut down your machine. Otherwise you
run the risk of damaging the file system.
Conclusion
Identity theft has quickly risen to crisis-level proportions.
Keeping your information under encryption will save you much grief.
The techniques I've described here are straightforward and
don't require much more than the standard tool set that is
available on today's open source platform. Be proactive and
protect your systems.
References
Links
SRA America -- http://sraapowergres.com
Bit Torrent -- http://www.bittorrent.com
PostgreSQL -- http://postgresql.org
Choicepoint identity theft -- http://www.msnbc.msn.com/id/6969799/
Identity theft conviction -- http://www.news10.net/storyfull10.asp?id=9611
New California privacy laws -- http://www.cio.com/archive/011505/california.html
Man Pages
dd
losetup
mke2fs
mkdir
mount
fstab
openssl
sudo
sudoers
visudo
Robert works as a consultant and has written for numerous magazines.
He is also a regular writer for O'Reilly's onlamp.com. Currently,
Robert is the PostgreSQL Business Intelligence Analyst at the Manhattan
offices of SRA, Software Research Associates, which specializes
in service and support for BSD and PostgreSQL. SRA (http://sraapowergres.com)
was founded in the 1960s and is among the world's oldest software
houses. Robert can be contacted at: robertb@sraapowergres.com. |