Whilst developing our customer support tool, one of the requirements I have is to capture and display password information for systems which we support. Even though we will ensure the application is SSL enabled and we will enforce some password expiration and complexity requirements we still felt there was a need to add additional security to the report which will show the information in encrypted format until a correct pass phrase is entered to decrypt the data server side.
I’m not entirely sure of the design and I’m hoping some people could provide feedback on the pro’s and cons of the approach and also let me know if you think it’s kind of redundant.
The design goes like this:
- We have a page process which runs “Before Header” which creates/truncates/creates our password report collection (based on a SQL query) on every page load. The password field in this collection is encrypted using “dbms_obfuscation_toolkit.DESEncrypt”. Note: the underlying password field is encrypted in the database and we use a static phrase to decrypt it within the collection build procedure and then re-encypt it with our changing passphrase. Also for every APEX page load the report data will be shown encrypted, but AJAX refreshes of the report i.e. pagination/filtering etc. will display unencrypted data if the user has decrypted the passwords).
- We provide a region button called “Decrypt” which pops up a dialog box for the user to enter a pass phrase.
- The pass phrase is sent to the server via an AJAX call and a test decrypt operation is performed, if it was successful we re-create the collection with unencrypted data and reload our report via an AJAX call (as the report queries the collection) you can use either Ext or $a_report. The reload will show the report data with unencrypted passwords. If the decrypt was unsuccessful we simply display an alert that it was unsuccessful, so a second attempt to decrypt can be made (rather than garbling the text).
- The pass phrase it self comes from a table with several thousand combinations and is selected based on the row number and a numeric representation of to_char on sysdate e.g. to_char(sysdate,’DDHH’). In order to randomize the data we reload the table nightly (or hourly depending up upon the required interval) and change the data ordering using “dbms_random.value” . The reason we have chosen this approach is that we need to ensure that we can return the same pass phrase for the given period, but at the same time ensure that there is no ability to guess what the phase might be for any given day, given our to_char format on sysdate is hard coded in the PLSQL.
FUNCTION get_random_phrase ( p_date_string IN VARCHAR2 ) RETURN VARCHAR2 AS BEGIN FOR c IN ( SELECT phrase_adj||' '||phrase_noun phrase FROM ( SELECT p.* , rownum rn , r.adj_rownum FROM portal_pass_phrases p , (SELECT portal_utils.baseX(to_number(to_char(sysdate, p_date_string)),r.r)+1 adj_rownum FROM ( SELECT count(*) r FROM portal_pass_phrases ) r ) r ) WHERE rn = adj_rownum ) LOOP RETURN c.phrase; END LOOP; RETURN NULL; EXCEPTION WHEN OTHERS THEN -- your custom error handling goes here RAISE; END get_random_phrase; - The users are notified of the pass phrase by publishing the phrase to a completely separate system which is visible to the support team, it’s embedded within a larger message (for example a news title) so it’s not obvious to anyone but those who have been told about it.
- The function for generating the pass phrase is a private function in the package body, the decrypt function is public but requires a valid pass phrase to be entered, however the decrypt with the static passphrase which decrypts the encrypted table data for rencryption with our changing pass phrase is a private procedure and only called during the build of our collection. Because we have the pass phrase generator as a private function we can encrypt a test string, decrypt it with the current random pass phrase, and check it against the pass phrase entered by the user for our checking purpose so everything is locked down .e.g.
f_decrypt(f_encrypt('testphrase'),get_random_phrase(gc_key_string)) = f_decrypt(f_encrypt('testphrase'),p_pass_phrase)The pass phrase is only valid as long as the length between the pass phrase table re-ordering which is scheduled by the dbms_scheduler, so we can easily change the frequency of the pass phrase lifetime by modifying the job schedule.
Here’s a couple of screenshots to give you a visual idea of how it hangs together, I’d be very grateful if someone could provide some feedback/discussion on the concept and provide any potential changes or recommendations…





Hi Matt,
I’m a bit concerned about your first sentence: “capture and display password information”. I’m always a bit hesitant about systems that store passwords in clear text. I think you should revisit that part and look at hashing the password. This may fix the problem altogether.
That being said, I know that you can’t always change things and must deal with that you’re given. How does the end user know the pass phrase?
Martin
Hi Martin
Thanks for the reply, unfortunately passwords are inherently insecure anyway you look at them
.
Unfortunately we can’t hash the passwords as the support teams need to read these in order to logon to all the systems we support. It’s impossible to remember over several thousand passwords acorss hundreds of systems for the support team, and every option of storing them has their own issues (we’re trying to move away from our current method of storing them). The passwords are stored in encrypted format in the database and decrypted by a private separate decrypt function which uses a persistent non changing pass phrase. This private decrypt is only called within our PLSQL procedure which creates the collection and re-encrypts the data using our changing pass phrase. So theoretically it should be secure??
The users are notified of the pass phrase by publishing the phrase to a completely separate system which is visible to the support team, it’s embedded within a larger message (for example a news title) so it’s not obvious to anyone but those who have been told about it.
Does this make it sound any better??
Cheers
Matt
Hi Matt,
Overall I understand the situation now and think the proposed solution is ok. If you had very very important information on it I would still disagree to storing a password that can be decrypted.
That being said it seems that you’re doing all this to work around the issue of the support team being able to login as another user. Perhaps you should look at updating your system to allow power users (in this case your support team) to “act like” regular users in the system. I’ve done this before on a small system. It does take a bit of design work but once you get it working it can be extremely useful.
Hope this helps,
Martin
Hi Martin
Thanks again for your reply, to further clarify, the usernames/passwords we store are not for the current application or a SAAS app but for sevrers, databases, app servers, applications, websites, SSH keys etc. (as we’re a remote support company).
However I do like your idea of switching access within an APEX app without/re-authentication. Something I’ll keep in mind design wise for future apps.
Cheers
Matt
Ahhh makes sense now… Yes I think what you’re doing is good.
As for the extra step for the passphrase. If the users have to access these passwords often they may get a bit frustrated with having to re-enter the passphrase. If they already have access to the system then just let them through.
Martin
it’s something we’ve implemented to re-assure our customers and let them know we’re focsued on security… I do think it is a little redundant , however it does lock things down a little if somone managed to hack into the application They would still have to hack the passphrase as well… which is constantly changing and something probably more secure than what an end user chooses for his/her password…
We support financial companies and other sensitive type sites so security is something we need to focus on… I’m still interested in hearing other design ideas for extra layers of security when it comes to storing and retrieving passwords stored in the database using APEX… do you have any alternative suggestions??
Matt