*Disclaimer: I am going to describe a symptom of a problem and provide a simple solution to address the symptom, not the problem :)
One of our products is a web based catalog engine that we host for our customers. We provide our customers with an administration tool they can use to setup end-user accounts (username/password) so they control who can view their catalogs. We also have a number of customers that integrate our catalog application into a broader offering of their own. Our customers want to take care of the user management through their own systems and simply redirect end-users from their site to our hosted catalog engine. The issue that arises in this case is when the our customer disables an end user account they want to prevent the end user from accessing our catalog application. If the end user has bookmarked our catalog engine, they can bypass the customers site and continue using our catalog engine.
One solution that may have popped into your head was to check the HTTP_REFERRER property on the request and match it against a known list of valid referrers. The problem with this approach is that HTTP_REFERRER can be very easily spoofed. There are a number of ways to address this issue but we needed something that was simple, repeatable, and required as little technical knowledge on the customer end as possible.
My quick solution was to implement one time pad (we aren't encrypting anything but I think the concept is still applicable) authentication to validate that the user was coming to our catalog engine from a trusted source. I'll show how to implement this solution using SQL Server but it can work with any relational database (you could even do it using a plain text file).
- Create a table to hold your pads.
CREATE TABLE OneTimePad
(
Pad UNIQUEIDENTIFIER
)
- Populate your table with pads.
SET NOCOUNT ON DECLARE @i BIGINT
SET @i=0
TRUNCATE TABLE OneTimePad
WHILE @i < 100000 BEGIN
INSERT INTO OneTimePad VALUES(NEWID())
SET @i = @i + 1
END
- Send a copy of the pad table to the customer.
- The customer will then append a pad to the url we give them to invoke our catalog engine. Here is a sample sproc to get the next pad:
CREATE PROC GetNextPad
AS
SET NOCOUNT ON
DECLARE @pad UNIQUEIDENTIFIER
BEGIN TRAN
SELECT TOP 1 @pad=Pad FROM OneTimePad;
DELETE FROM OneTimePad WHERE Pad=@pad;
COMMIT
SELECT @pad;
GO
- On our landing page, we check for the presence of the pad parameter. If it's not present, we send them back to the customer site. If the pad is invalid, we tell them to take a hike. Here's the pseudo code:
pad = Request.QueryString["pad"]
if( null == pad ) redirect back to customer site
recordsAffected = exec("DELETE FROM OneTimePad WHERE Pad=?", pad)
if( 0 == recordsAffected ) die "We're unhackable biatch!"
Our site forces end-users to access us through our landing page. We only have to validate them when they get redirected from a customer. Once those steps are in place we have a poor mans referrer authentication that is fairly solid and easily repeatable for other customers/hosted products. We have the option to generate a gajillion keys or setup an FTP based key exchange. The only way to compromise the system is to brute force it (good luck with that) or to compromise the pad database. If the latter occurs, simply regenerate and exchange new pads.
I'm counting on you the reader to poke holes in this proof of concept :)
posted @ Friday, May 25, 2007 6:25 PM