Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

hide an argument

Status
Not open for further replies.

imad77

Instructor
Oct 18, 2008
97
0
0
CA
Hi,

I developed a Perl script script1.pl where we can click on a hyperlink and it calls another script download.pl to list a directory or download a file with an argument.

print qq~ <a href="download.pl?file=$file">$file</a><br>
~;

But people can see the entire path in the argument $ file passed as a variable from script1.pl to download.pl and they can change the path and access to other directory. Can I hide this argument "?file=$file" ?
or use another way to pass my variables to another script after clicking to the hyperlink?

Is it a way to perform these actions in Perl?

Thanks a lot.
 
The link as you posted it sends a GET request for download.pl and therefore has to send all its arguments in the query string, where they're visible. To hide arguments you need to do a POST request, and afaik the only way to do that is to use an HTML form.

You could do something like this:

Code:
<form name="download" action="download.pl" method="post">
<input type="hidden" name="file" value="$file">

<a href="#" onClick="document.forms['download'].submit(); return false">$file</a>

<!-- or -->
<input type="submit" value="$file">

</form>

With some JavaScript leetness, you could make a function that dynamically creates a new form and turns all parameters into hidden input fields and then submits that. And that way you could have any random link send its args hidden without having to write out new forms for each link.

-------------
Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
This was interesting, so I went ahead and wrote a JavaScript that does what I mentioned in my last post: turns a regular <a href> into a new form and submits it.

Code:
[kirsle@firefly poster]$ cat test.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"[URL unfurl="true"]http://www.w3.org/TR/html4/strict.dtd">[/URL]
<html>
<head>
<title>Test</title>
</head>
<body>

<a href="test.cgi?hello=world&something=else&a=b&c=d"
onClick="return doPost(this)">Link #1</a><p>

<a href="test.cgi?abc=def;hij=klm;nop=qrs">Another Link</a>

<script type="text/javascript">
function doPost(obj) {
   var uri = obj.href;
   var pts = uri.split("?");
   var cgi = pts[0];
   var query = "";
   if (pts[1].length > 0) {
      query = uri.substr((cgi.length + 1), (uri.length - cgi.length));
   }

   // & or ;-delimited?
   var fields = {};
   var parts  = new Array();
   var names  = new Array();
   if (query.length > 0) {
      if (query.indexOf("&") > -1) {
         parts = query.split("&");
      }
      else if (query.indexOf(";") > -1) {
         parts = query.split(";");
      }
   }
   if (parts.length > 0) {
      for (var i = 0; i < parts.length; i++) {
         var vars = parts[i].split("=");
         var what = vars[0];
         var is = parts[i].substr((what.length + 1), (parts[i].length - what.length));
//         window.alert(what + " => " + is);
         fields[what] = is;
         names[i] = what;
      }
   }

   // Generate a form.
   var rand = Math.floor(Math.random() * 99999);
   var frm = document.createElement("form");
   frm.name = "autoform" + rand;
   frm.action = cgi;
   frm.method = "post";

   // Create inputs.
   for (var i = 0; i < names.length; i++) {
      var input = document.createElement("input");
      input.type = "hidden";
      input.name = names[i];
      input.value = fields[ names[i] ];
//      window.alert("add input [" + names[i] + "] : [" + fields[names[i]] + "]");
      frm.appendChild(input);
   }

   // Append the form.
   document.body.appendChild(frm);

   // Submit the form.
   document.forms["autoform" + rand].submit();

   return false;
}
</script>

</body>
</html>

[kirsle@firefly poster]$ cat test.cgi
#!/usr/bin/perl -w

use strict;
use warnings;
use CGI;

my $q = new CGI;

print $q->header;
print "<ul>\n";
foreach my $what ($q->param) {
   print "<li>$what = " . $q->param($what) . "</li>\n";
}
print "</ul>\n";

-------------
Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Actually

Code:
<a href="test.cgi?abc=def;hij=klm;nop=qrs">Another Link</a>

needs to be

<a href="test.cgi?abc=def;hij=klm;nop=qrs" onClick="return doPost(this)">Another Link</a>

-------------
Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
You should not put the full path to the file in the link, just the filename or a code that points to the file, like "file=1234", where you script knows what "1234" is. The full path to the file should be hard coded in the perl script. If for some reason that is not possible you can encode the file path and decode it in your perl script. But you should still write a good filtering/validation routine in your perl code to prevent people from altering the path and accessing other parts of the site. Using javascript is not the way to go as it only works in the browser. Hidden form fields are also not secure.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
lol, a couple other things:

1) To hide the args even from the original <a href> (because the real URL will appear in the browser's status bar, even though the query string won't be visible in the URL after the link is clicked), you could put the query string inside a different attribute, such as "rel" or "class" or anything made up...

Code:
<a href="#" rel="test.cgi?hello=world" onClick="doPost(this)">

...and then in the JS, instead of this...
var uri = obj.href;

...do this...
var uri = obj.rel;
...or...
var uri = obj.getAttribute("rel");


Example with a custom attribute:
<a href="#" secret="test.cgi?hello=world" onClick="return doPost(this)">

...and...
var uri = obj.getAttribute("secret");

Note that custom attributes will cause your page to not pass validation if you use the W3C HTML validator tools.

2) Have JavaScript automate stuff to make it easier

Another thing you can do if you don't want to copy the "return doPost()" thing on every single link is, give a common attribute to each link to identify it as one that you want to apply this to. And then add this additional JavaScript code

Code:
<a href="test.cgi?hello=world" class="secret">click me!</a>

<script type="text/javascript">
document.onload = init();

function init() {
   // Loop through every A tag on the page
   var lynx = document.getElementsByTagName("a");
   for (var i = 0; i < lynx.length; i++) {
      // See if this link has the "secret" class
      if (lynx[i].className == "secret") {
        // Apply onClick="return doPost(this)" to this link
        lynx[i].onclick = function(obj) {
          return doPost(obj);
        };
      }
   }
}

And instead of using classes and lynx.className, you can use a custom attribute and do lynx.getAttribute() or w/e like I mentioned above.

-------------
Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Hi,

Thanks a lot for your help. I tried it but the real URL will appear in the browser's status bar like

and when I click on the link "click me!", the real URL will appear in the browser's address bar.

Here is the complete script test.html. Is there something wrong?

Thanks a lot.

======================
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"<html>
<head>
<title>Test</title>
</head>
<body>

<a href="test.cgi?hello=world" class="secret">click me!</a>

<a href="test.cgi?abc=def;hij=klm;nop=qrs">Another Link</a>

<script type="text/javascript">
document.onload = init();

function init() {
// Loop through every A tag on the page
var lynx = document.getElementsByTagName("a");
for (var i = 0; i < lynx.length; i++) {
// See if this link has the "secret" class
if (lynx.className == "secret") {
// Apply onClick="return doPost(this)" to this link
lynx.onclick = function(obj) {
return doPost(obj);
};
}
}
}
function doPost(obj) {
var uri = obj.getAttribute("secret");
var pts = uri.split("?");
var cgi = pts[0];
var query = "";
if (pts[1].length > 0) {
query = uri.substr((cgi.length + 1), (uri.length - cgi.length));
}

// & or ;-delimited?
var fields = {};
var parts = new Array();
var names = new Array();
if (query.length > 0) {
if (query.indexOf("&") > -1) {
parts = query.split("&");
}
else if (query.indexOf(";") > -1) {
parts = query.split(";");
}
}
if (parts.length > 0) {
for (var i = 0; i < parts.length; i++) {
var vars = parts.split("=");
var what = vars[0];
var is = parts.substr((what.length + 1), (parts.length - what.length));
// window.alert(what + " => " + is);
fields[what] = is;
names = what;
}
}

// Generate a form.
var rand = Math.floor(Math.random() * 99999);
var frm = document.createElement("form");
frm.name = "autoform" + rand;
frm.action = cgi;
frm.method = "post";

// Create inputs.
for (var i = 0; i < names.length; i++) {
var input = document.createElement("input");
input.type = "hidden";
input.name = names;
input.value = fields[ names ];
// window.alert("add input [" + names + "] : [" + fields[names] + "]");
frm.appendChild(input);
}

// Append the form.
document.body.appendChild(frm);

// Submit the form.
document.forms["autoform" + rand].submit();

return false;
}
</script>

</body>
</html>
 
IMHO, this is not the way to go. Use perl to encode your file path and perl to decode the file path. Javascript provides no real security.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Unless you are using multiple directories to download files from, you should only use the filename in the URI, and hard code the download directory in the perl script. Filter out any "dangerous" characters from the filename sent to your script. There should be no '\' or '/' or '.' in the filename sent to the script as those can be used to access other directories on the server.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
What's wrong with that code is that I haven't tested it. :p I only tested the first large chunk of JavaScript I posted. The rest were kinda on-the-fly bits of example code.

Kevin's right about how you should handle the download function from the Perl side. You should never trust input from the user to be okay. Even if 99% of your users won't try to mess up your site and send it bad data and potentially damage things, there's always the 1% who might. So trying to hide data in the web browser to prevent users from tampering with it and finding ways to make your script behave how you didn't intend to isn't a very good idea. All it takes is for somebody to view the source, see what's going on with the form and the link to your CGI, copy all that out of there and manually type in a URL but try poking around at it by putting different values into the query string, and then ya could be in some trouble.

Similarly: your CGI should never assume that "hidden" input fields can't be modified, or "readonly" or "disabled" input fields. Don't even rely on the "maxlength" attribute either. All of these things only limit what the user can do inside their web browser, and there are dozens of plugins for Firefox (for example) that can let the users remove readonly, disabled, maxlength restrictions, make hidden fields editable, and every other possible thing one can do to mess up a web form. So everything you don't want your users to do on their end, your Perl script should double check on its end just to make sure.

-------------
Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top