HMAC Verification
چهارشنبه, ۳۰ آذر ۱۳۹۰، ۰۶:۳۵ ب.ظ
توی یکی از کتاب هایی که داشتم مطالعه می کردم به موضوع جالبی در مورد امنیت URL ها رسیدم که بد ندیدم اونو با شاما دوستان به اشتراک بزارم.
Validate کردن داده های ارسالی یا همون آرگومان ها جزو اصول اولیه تضمین امنیت برای یک برنامه هستش. راه حل های مختلفی مثل استفاده کردن از White/Black List, Escaping و .... وجود داره. ولی حقیقت اینه که دور زدن این مدل از بررسی صحت داده ها برای یک کرکر کار درست, چندان سخت نیست.....
HMAC Verification روشی هست که تو این پست قصد داریم نگاهیی به اون داشته باشیم. خلاصه روش این هست که از آرگومان های ارسالی یک هش درست می کنیم و اون رو به همراه خود آرگومان ها ارسال می کنیم که اگر یه زمانی یه کرکر با آرگومانهای ما شلوغ کاری کرد سیستم Validation ما قابل دور زدن نباشه.
این کلاس یک نمومه ساده از پیاده سازی این روش هستش.
[sourcecode language="php"]
function create_parameters($array) {
$data = '';
$ret = array();
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$hash = md5($data); // sha1($data) or any hashing func you want
$ret[] = "hash=$hash";
return join ('&', $ret); // you can use implode instead of join
}
echo ' Target URL ';
// out put:
// Target URL
[/sourcecode]
خوب این روش اول کمی ساده هستش و با Brute Force و یا یکم حرفه ای تر به کمک Rainbow ها قابل دور زدن هستش. حالا اگه از روش HMAC استفاده کنیم دیگه می شه گفت که امنیت این قسمت از برنامه رو تضمین کردیم.
کلاسی که الان معرفی می شه برای هش کردن داده ها به کمک یک کلید مخقی هستش که خودمون تعیین می کنیم.
[sourcecode language="php"]
// Crypt/HMAC.php
class Crypt_HMAC {
/**
* Constructor
* Pass method as first parameter
*
* @param string method - Hash function used for the calculation
* @return void
* @access public
*/
function Crypt_HMAC($key, $method = 'md5') {
if (!in_array($method, array('sha1', 'md5'))) {
die("Unsupported hash function '$method'.");
}
$this->_func = $method;
/* Pad the key as the RFC wishes (step 1) */
if (strlen($key) > 64) {
$key = pack('H32', $method($key));
}
if (strlen($key) _ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
$this->_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
}
/**
* Hashing function
*
* @param string data - string that will hashed (step 4)
* @return string
* @access public
*/
function hash($data) {
$func = $this->_func;
$inner = pack('H32', $func($this->_ipad . $data));
$digest = $func($this->_opad . $inner);
return $digest;
}
}
[/sourcecode]
برای استفاده کردن از این کلاس هم سلایق می تونه متفاوت باشه. در زیر یه نمونه از پیاده سازی نهایی و در نهایت بررسی صحت داده ها بعد از دریافت URL هش شده برای شما آماده کردم.
[sourcecode language="php"]
require_once('Crypt/HMAC.php');
/* The RFC recommends a key size larger than the output hash
* for the hash function you use (16 for md5() and 20 for sha1()). */
define ('SECRET_KEY', 'Professional PHP 5 Programming Example');
function create_parameters($array) {
$data = '';
$ret = array();
/* Construct the string with our key/value pairs */
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$h = new Crypt_HMAC(SECRET_KEY, 'md5');
$hash = $h->hash($data);
$ret[] = "hash=$hash";
return join ('&', $ret);
}
echo 'URL!';
// output
// URL!
[/sourcecode]
[sourcecode language="php"]
// To verify the parameters passed to the script, we can use this script:
require_once('Crypt/HMAC.php');
define ('SECRET_KEY', 'Professional PHP 5 Programming Example');
function verify_parameters($array) {
$data = '';
$ret = array();
/* Store the hash in a separate variable and unset the hash from
* the array itself (as it was not used in constructing the hash
*/
$hash = $array['hash'];
unset ($array['hash']);
/* Construct the string with our key/value pairs */
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$h = new Crypt_HMAC(SECRET_KEY, 'md5');
if ($hash != $h->hash($data)) {
return FALSE;
} else {
return TRUE;
}
}
/* We use a static array here, but in real life you would be using
* $array = $_GET or similar. */
$array = array(
'cause' => 'vars',
'hash' => '6a0af635f1bbfb100297202ccd6dce53'
);
if (!verify_parameters($array)) {
die("Dweep! Somebody tampered with our parameters.n");
} else {
echo "Good guys, they didn't touch our stuff!!";
}
[/sourcecode]
نکته: این موارد می تونه خیلی کامل تر هم باشه ولی خوب فعلا همین قدر سواد داریم.
مثلا می شه با اضافه کردن session و یا ذخیره کردن هش ها تو پایگاه داده بازهم امنیت رو بیشتر کرد.
در کل امنیت جزیی از سیستم هستش و به نظر من معیار کارایی هم به حساب می آید. پایان
Validate کردن داده های ارسالی یا همون آرگومان ها جزو اصول اولیه تضمین امنیت برای یک برنامه هستش. راه حل های مختلفی مثل استفاده کردن از White/Black List, Escaping و .... وجود داره. ولی حقیقت اینه که دور زدن این مدل از بررسی صحت داده ها برای یک کرکر کار درست, چندان سخت نیست.....
HMAC Verification روشی هست که تو این پست قصد داریم نگاهیی به اون داشته باشیم. خلاصه روش این هست که از آرگومان های ارسالی یک هش درست می کنیم و اون رو به همراه خود آرگومان ها ارسال می کنیم که اگر یه زمانی یه کرکر با آرگومانهای ما شلوغ کاری کرد سیستم Validation ما قابل دور زدن نباشه.
این کلاس یک نمومه ساده از پیاده سازی این روش هستش.
[sourcecode language="php"]
function create_parameters($array) {
$data = '';
$ret = array();
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$hash = md5($data); // sha1($data) or any hashing func you want
$ret[] = "hash=$hash";
return join ('&', $ret); // you can use implode instead of join
}
echo ' Target URL ';
// out put:
// Target URL
[/sourcecode]
خوب این روش اول کمی ساده هستش و با Brute Force و یا یکم حرفه ای تر به کمک Rainbow ها قابل دور زدن هستش. حالا اگه از روش HMAC استفاده کنیم دیگه می شه گفت که امنیت این قسمت از برنامه رو تضمین کردیم.
کلاسی که الان معرفی می شه برای هش کردن داده ها به کمک یک کلید مخقی هستش که خودمون تعیین می کنیم.
[sourcecode language="php"]
// Crypt/HMAC.php
class Crypt_HMAC {
/**
* Constructor
* Pass method as first parameter
*
* @param string method - Hash function used for the calculation
* @return void
* @access public
*/
function Crypt_HMAC($key, $method = 'md5') {
if (!in_array($method, array('sha1', 'md5'))) {
die("Unsupported hash function '$method'.");
}
$this->_func = $method;
/* Pad the key as the RFC wishes (step 1) */
if (strlen($key) > 64) {
$key = pack('H32', $method($key));
}
if (strlen($key) _ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
$this->_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
}
/**
* Hashing function
*
* @param string data - string that will hashed (step 4)
* @return string
* @access public
*/
function hash($data) {
$func = $this->_func;
$inner = pack('H32', $func($this->_ipad . $data));
$digest = $func($this->_opad . $inner);
return $digest;
}
}
[/sourcecode]
برای استفاده کردن از این کلاس هم سلایق می تونه متفاوت باشه. در زیر یه نمونه از پیاده سازی نهایی و در نهایت بررسی صحت داده ها بعد از دریافت URL هش شده برای شما آماده کردم.
[sourcecode language="php"]
require_once('Crypt/HMAC.php');
/* The RFC recommends a key size larger than the output hash
* for the hash function you use (16 for md5() and 20 for sha1()). */
define ('SECRET_KEY', 'Professional PHP 5 Programming Example');
function create_parameters($array) {
$data = '';
$ret = array();
/* Construct the string with our key/value pairs */
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$h = new Crypt_HMAC(SECRET_KEY, 'md5');
$hash = $h->hash($data);
$ret[] = "hash=$hash";
return join ('&', $ret);
}
echo 'URL!';
// output
// URL!
[/sourcecode]
[sourcecode language="php"]
// To verify the parameters passed to the script, we can use this script:
require_once('Crypt/HMAC.php');
define ('SECRET_KEY', 'Professional PHP 5 Programming Example');
function verify_parameters($array) {
$data = '';
$ret = array();
/* Store the hash in a separate variable and unset the hash from
* the array itself (as it was not used in constructing the hash
*/
$hash = $array['hash'];
unset ($array['hash']);
/* Construct the string with our key/value pairs */
foreach ($array as $key => $value) {
$data .= $key . $value;
$ret[] = "$key=$value";
}
$h = new Crypt_HMAC(SECRET_KEY, 'md5');
if ($hash != $h->hash($data)) {
return FALSE;
} else {
return TRUE;
}
}
/* We use a static array here, but in real life you would be using
* $array = $_GET or similar. */
$array = array(
'cause' => 'vars',
'hash' => '6a0af635f1bbfb100297202ccd6dce53'
);
if (!verify_parameters($array)) {
die("Dweep! Somebody tampered with our parameters.n");
} else {
echo "Good guys, they didn't touch our stuff!!";
}
[/sourcecode]
نکته: این موارد می تونه خیلی کامل تر هم باشه ولی خوب فعلا همین قدر سواد داریم.
مثلا می شه با اضافه کردن session و یا ذخیره کردن هش ها تو پایگاه داده بازهم امنیت رو بیشتر کرد.
در کل امنیت جزیی از سیستم هستش و به نظر من معیار کارایی هم به حساب می آید. پایان
استفاده از md5sum بهترین روش برای validate کردن درخواستها و اجرای اسکریپتهاست.