I use routines similar to what you're doing, though I tend to explicitly write out the hidden fields, since our company doesn't use templates (sigh). One common problem with hidden data is that those hidden values can easily be tampered with. If that's not important to you, it's not a big deal. However, you could have problems if you rely on something like the following:
<input type=hidden name="price" value="42.95">
Then, it can be a trivial matter for someone to adjust the price value. Needless to say, if you have other data in those fields that you cannot afford to have altered, this can be a big problem. Try using Digest::MD5 or Digest::SHA1 (SHA1 takes longer, but it's more secure). Here's some sample code:
#!/usr/bin/perl -w
use strict;
use Digest::MD5 qw ( md5_base64 );
my $rand = 'yed*73=1/+#@%d';
my $price = '40.95';
my @data = ($rand, $price);
my $base64_digest = md5_base64( @data );
print $base64_digest;
That should print something like "BS1+1ySMDuN+fqp7hnMRYw".
Take the digest value and embed that in the form. When the values are returned, recompute the digest with the same $rand. If the values don't match, your hidden values have been tampered with. Needless to say, you want $rand to be as secure as possible!
Cheers,
Ovid
Join the Perlmonks Setiathome Group or just go the the link and check out our stats. | [reply] [d/l] [select] |
Thanks for the tip Ovid. I use a similar scheme sometimes myself. I learned about this from Writing Apache modules, page 213. In the explanation, they say that you should run the MD5 algorithm twice or "Otherwise, a technically savvy user could take advantage of one of the mathematical properties of the algorithm to append his own data to the end of the fields". They give this example:
$MAC = MD5->hashhex($secret .
MD5->hashex(join '',$secret, @fields) );
| [reply] [d/l] |
Why not use server side sessions to do that?
(eg. with Apache::Session) | [reply] |
I do use server side sessions for a lot of things, but I don't use them all the time because sometimes I simply want to pass data between two forms, and I'm not passing sensitive data, and I'm not 'eval'ing it or using it to create file names, so I have minimal security concerns about the data being hijacked. Adding Apache::Session to the project would add a lot of complexity to the project (it's a lot more code that a bug could potentionally be in. As they say "code deleted (or not used) is code debugged").
For more complex projects, such as shopping cart systems, I do use server side sessions, but I usually roll my own using a SQL database, rather than adding in the complexity of Apache::Session. It's features of serialization and locking are already provided by the database, retreiving data is done easily through DBI's fetchrow_hashref, and I can insert data easily through CGI::SQL's &insert_from_param function. Furthermore, I'm not tied to having my session table named a particular thing, or having the columns named a particular way.
| [reply] |
I would have to agree with cianoz -- pass state through sessions,
and only pass the session key as a hidden variable, or in a
cookie. The problem with passing state through a form, besides
having to encode/decode it every time, is that you have to
untaint/revalidate it every time to keep people from hijacking
your variables to their own nefarious ends. If you pass a session
key around, they can mess with the key, but the most they can do
with a good MD5-hashed key is invalidate their session. | [reply] |
Under HTML::Embperl this is a snap. On each HTML page that you want hidden fields created for the CGI data passed in your webpage must simply look like this:
<form>
[$ hidden $]
</form>
And Embperl expands it's hidden tag into the CGI query data automatically.
For comparison, this is not available under HTML::Mason and I cannot comment on the other fairly complete web application frameworks (HTML::EP, Apache::PageKit, and BingoX (which is on sourceforge, not CPAN) with regard to this feature.
| [reply] [d/l] |