views:

248

answers:

3

I want to pass a serialized Perl data structure as a GET variable to a CGI application. I tried Data::Serializer as my first option. Unfortunately the serialized string is too long for my comfort, in addition to containing options joined by '^' (a caret).

Is there a way I can create short encoded strings from perl data structures so that I can safely pass them as GET variables to a perl CGI application?

I would also appreciate being told that this (serialized, encoded strings) is a bad way to pass complex data structures to web applications and suggestions on how I could accomplish this

+1  A: 

Passing serialized encoded strings is a bad way to pass complex data structures to web applications.

If you are trying to pass state from page to page, you can use server side sessions which would only require you to pass around a session key.

If you need to email a link to someone, you can still create a server-side session with a reasonable expiry time (you'll also need to decide if additional authentication is necessary) and then send the session id in the link. You can/should expire the session immediately once the requested action is taken.

Sinan Ünür
"this" would be "passing a data structure to a CGI application". You are right about using sessions being the right way of passing data from page to page. However, the situation I have is that I want to create a link (URL) and mail it to an email address. When the recipient of the mail clicks on the link, I want to have access to all data corresponding to that user to handle his request (unsubscribe from a mailing list for example)
Gurunandan
Nothing! Other than the fact that I never thought you could do this :). Will definitely evaluate this - Thanks
Gurunandan
@Gurunandan Bhat: FYI: I deleted my comment and put my suggestion in the answer itself.
Sinan Ünür
@Gurunandan Bhat: Why would you have to create thousands of server side sessions?
Sinan Ünür
Sorry - Might not work for what I want to do. On first thoughts, would have to create thousands of server-side sessions one for each recipient. Seems excessive on first thoughts. Or am I reading you incorrectly?
Gurunandan
How else would I maintain separate data sctructures for each recipient?
Gurunandan
@Gurunandan Bhat: Aren't these links created on demand? I am not getting the sneaking suspicion that you want to include these links in the footer of some commercial email you want to send. In that case, why don't use the email address as the key to look up the associated data in the database?
Sinan Ünür
Footer- Yes. Commercial Email: No. The link leads to a Comment form in a Web Forum to Email gateway (not different from an internally hosted Yahoo Groups for example) where the recipient has a choice of replying to the email or clicking a link to enter his response can respond directly to the forum (which is further emailed..etc.). I cant expose the email address to prevent someone spoofing a response. Authentication is alas not an option
Gurunandan
@Gurunandan Bhat: One way or another, the **right** solution will be to send a key to some table. It does not have to be an email address in plain sight but it needs to be a key to a database entry (and I don't see how sending a full encoded data structure is any safer).
Sinan Ünür
+1  A: 
Corey Porter
Agreed that using Storable/Serializer are not portable across languages. Would be interested in hearing how you plan to solve your problem.
Gurunandan
+1  A: 

If you need to send URL's to your users that contains a few key datapoints and you want to ensure it can't be forged you can do this with a Digest (such as from Digest::SHA) and a shared secret. This lets you put the data out there in your messages without needing to keep a local database to track it all. My example doesn't include a time element, but that would be easy enough to add in if you want.

use Digest::SHA qw(sha1_base64);
my $base_url = 'http://example.com/thing.cgi';

my $email = '[email protected]';
my $msg_id = '123411';

my $secret = 'mysecret';
my $data = join(":", $email, $msg_id, $secret);
my $digest = sha1_base64($data);

my $url = $base_url . '?email=' . $email . '&msg_id=' . $msg_id' . '&sign=' . $digest;

Then send it along.

In your "thing.cgi" script you just need to extract the parameters and see if the digest submitted in the script matches the one you locally regenerate (using $email and $msg_id, and of course your $secret). If they don't match, don't authorize them, if they do then you have a legitimately authorized request.

Footnote:
I wrote the "raw" methods into Data::Serializer to make translating between serializers much easier and that in fact does help with going between languages (to a point). But that of course is a separate discussion as you really shouldn't ever use a serializer for exchanging data on a web form.

Neil Neely
Thanks - this is exactly what I was looking for.
Gurunandan