Author Topic: secure _POST requests  (Read 4397 times)

Offline crnogorac081

  • Posts: 1912
  • Gender: Male
secure _POST requests
« on: April 04, 2010, 11:05:25 AM »
Hi,

By considering some latest issues, I was little bit concerned how to make sure that _POST request is proccessed only if is sent by some specific page.

For example if you post a Form from Page 1, and action is on Page 2, I wanted to make sure that it is not possible to proccess POST requests sent from another (remote) page/ site..

It becomes more important when I use forms for frontend editing , and JQuery post requests, so I can not include admin wrapper script.

Here is a code I would like to share:

Code: [Select]
<?php //color your live ;)
if(isset($_POST[&#39;page_id&#39;]) AND is_numeric($_POST[&#39;page_id&#39;]) ) {
$page_id =  mysql_real_escape_string(strip_tags($_POST[&#39;page_id&#39;])); } else { $page_id = &#39;&#39;;}

// create _SELF_ link, For testing hacker attempt below !!

// Get page extension - .php
$query_main_sett $database->query("SELECT * FROM `".TABLE_PREFIX."settings` WHERE name = &#39;page_extension&#39; ");
$wb_main_sett $query_main_sett->fetchRow();
$wb_default_page_extension $wb_main_sett[&#39;value&#39;];

// Get PAGES directory
$query_main_sett1 $database->query("SELECT * FROM `".TABLE_PREFIX."settings` WHERE name = &#39;pages_directory&#39; ");
$wb_main_sett1 $query_main_sett1->fetchRow();
$wb_default_pages_folder $wb_main_sett1[&#39;value&#39;];

//Get page name from page_id
$query_pages $database->query("SELECT * FROM `".TABLE_PREFIX."pages` WHERE page_id = &#39;$page_id&#39; ");
$this_page $query_pages->fetchRow();
$self_link WB_URL.$wb_default_pages_folder.$this_page[&#39;link&#39;].$wb_default_page_extension;


// Now, for my purposes, I needed additional variable to be icluded in URL string
if(isset($_POST[&#39;com_id&#39;]) AND is_numeric($_POST[&#39;com_id&#39;]) ) {
$com_id =  mysql_real_escape_string(strip_tags($_POST[&#39;com_id&#39;])); } else { $com_id = &#39;&#39;;}

// Prevent Hacking POST form
$caller $_SERVER[&#39;HTTP_REFERER&#39;];
$test $self_link.&#39;?&#39;.$COMPANIES[&#39;FE_ACTION&#39;].&#39;=&#39;.$COMPANIES[&#39;FE_VIEW_COM&#39;].&#39;&&#39;.$COMPANIES[&#39;FE_COM_NAME&#39;].&#39;=&#39;.$com_id;
if ($caller != $test) { $match = &#39;bad&#39;;} else { $match = &#39;OK&#39;;}

if (($com_id == &#39;&#39;) OR ($page_id == &#39;&#39;) OR ($match == &#39;bad&#39;)) {
die(header(&#39;Location: ../../index.php&#39;));
}


In this example in my case:
Code: [Select]
<?php //color your live ;)
$test http://127.0.0.1:4001/xo/me/companies.php?action=see-company&company=2
and this is the page from which _POST request is sent to another file, where above code is inserted to ensure that nobody can send you _POST request from remote host and alter your data..

So, consider this code while developing your addons.. :-D

All best,
Ivan
« Last Edit: April 06, 2010, 08:50:51 AM by mr-fan »
no bb in signature

Offline thorn

  • Posts: 980
  • Gender: Male
    • Projects
Re: secure _POST requests
« Reply #1 on: April 04, 2010, 01:04:49 PM »
Hello,

wow, that's a very complicated method.

Maybe, a far more simpler method is to use the plain old captcha-method (without displaying a captcha, indeed).

File 1:
Code: [Select]
<?php
$ident 
mt_rand();
$_SESSION[&#39;pagename_here_ident&#39;] = $ident;

// display form
?>

<form method="post" action="...">
<input type="hidden" name="ident" value="<?php echo $ident?>">
...

File 2:
Code: [Select]
<?php
if(!isset($_POST[&#39;ident&#39;]) || !isset($_SESSION[&#39;pagename_here_ident&#39;]) || $_POST[&#39;ident&#39;]!=$_SESSION[&#39;pagename_here_ident&#39;]) {
  // form faked
  
die(header("Location: ../../index.php"));
}
unset(
$_SESSION[&#39;pagename_here_ident&#39;]);

// rest here


thorn.

Waldschwein

  • Guest
Re: secure _POST requests
« Reply #2 on: April 04, 2010, 01:31:09 PM »
Hello!

Post is quite secure, but not very secure.
Better is using tokens for every form and link_hashes for every link.

I can't give you any code (because if I could I would have done it...), but the method is like:

Every upload, field, ... is a form. All forms have to "pass" a Control inside WebsiteBaker. I doesn't matter if such form is in frontend, backend, module or core.
Every form get's an individual token, e.g. "add_form_key('guestbook_bigtext');".Then the token gets validated via check_form_key('guestbook_bigtext');
So every post is controlled quite good.

Next one - link hashes. First every log-in in backend / frontend get's a link_hash, like    "_http://www._that_your_wb_url/.....&hash=" . generate_link_hash("{$mode}_$match_id"))".
So the link to http://www.yourwb.xy/admin/index.php will look now like http://www.yourwb.xy/admin/index.php&hash=423423hchd8329rhqeuwaiweur
Ok, then we combine every token with it and reading the hash:
$token = request_var('hash', '');
check_link_hash($token, "{$mode}_$match_id")

So - every token from above first checks if the link-hash is correct. If it isn't, no form (guestbook, upload, whatever needs a _POST and more...) could be used.

It's of course a very big thing, and something WB has to handle (a module that does that is _absolutely_ useless), but it could be worth... If that would have been in WB, nobody could use the backup-exploit. Because it first would check the hash - it is quite hard I heard guessing a 20 digits token - about 10^32 : 1.  :wink:

Yours Michael

Edit: Of course every hash needs to be controlled via cookie / AND destroyed after 30 minutes and that. It doesn't make sense using a hash for a week - people are easily sharing links with tokens (you know that e.g. from SMF here, that uses hashes in links).
« Last Edit: April 04, 2010, 01:36:11 PM by Waldschwein »

Offline thorn

  • Posts: 980
  • Gender: Male
    • Projects
Re: secure _POST requests
« Reply #3 on: April 04, 2010, 03:08:19 PM »
Hello,

hm, that's far more complicated -- but is it more secure?

Every upload, field, ... is a form. All forms have to "pass" a Control inside WebsiteBaker. I doesn't matter if such form is in frontend, backend, module or core.
Every form get's an individual token, e.g. "add_form_key('guestbook_bigtext');".Then the token gets validated via check_form_key('guestbook_bigtext');
So every post is controlled quite good.
That's exactly what i wrote above (just replace ident by token) -- but it is more complicated by usage of functions/methods a user has to know.
Nevertheless, a mandatory and consistent method may be a good thing :-)

Quote
Next one - link hashes. First every log-in in backend / frontend get's a link_hash
For logged-in users there is already a method to make links secure:
Usage of admin-class!

Quote
If that would have been in WB, nobody could use the backup-exploit
Nobody would have been able to use that exploit if the instantiating of the admin-class wasn't removed by accident before.


thorn.

Offline crnogorac081

  • Posts: 1912
  • Gender: Male
Re: secure _POST requests
« Reply #4 on: April 04, 2010, 09:17:26 PM »
Yes, you are right thorn,

Your code is much simplier and I like it.. In my code I just combined recent code for controling post form...

cheers
no bb in signature

 

postern-length