CakePHP reading encrypted cookie values - php

I set cookies like this:
$this->Cookie->write('mycookie', $data, TRUE, '30 days');
And I read them like this:
$cookieData = $this->Cookie->read('mycookie');
But for security concerns I read some of the cookies like this:
$cookieRaw= $_COOKIE['CakeCookie']['mycookie'];
And I write this raw cookie to my database. Then I need to read the content of the cookie.
But as you know raw cookie is something like "Q2FrZQ=dsdsaDASDasdasdsa".
So I need to read the content of the cookie.
It seems like CookieComponent:read() uses protected CookieComponent:_decrypt function. I don't want to copy paste the _decrypt() contents. Is there an easier way to read decrypted CakePHP strings ?

I don't see a reason for not using CookieComponent, for your information this component DO encrypt whatever you write. Here is an extract of the documentation
All values in the cookie are encrypted by default. If you want to store the values as plain-text, set the third parameter of the write() method to false. The encryption performed on cookie values is fairly uncomplicated encryption system. It uses Security.salt and a predefined Configure class var Security.cipherSeed to encrypt values. To make your cookies more secure you should change Security.cipherSeed in app/Config/core.php to ensure a better encryption.:

If you need to store the data encrypted, then I'd suggest to encrypt it yourself instead of relying on the cookie component internals.
ie, read the cookie data using the cookie component so that you end up with the decrypted data, then encrypt it with your favorite encryption algorithm (I'd suggest to use Security::rijndael()) and store it in the database, that way you have proper control over the data.
Another option would be to create a custom component that extends the cookie component and makes the decrypting functionality public. However I really don't think that's a good idea, the data in the DB shouldn't be a components concern, this is something that fits way better in the model layer.
If you insist using the mundged cookie data and decrypting it manually, then you'll have to do the same as can be seen in the CookieComponent code. First strip the Q2FrZQ==. from the data, then base64 decode it, afterwards decrypt it according to the method used by the cookie component (Security::cipher() by default, which is btw deprecated), and finally JSON decode it if necessary as in CookieComponent::_explode().
Assuming that only Cake 2.x style cookie data is used, and that the data is expected to be always encrypted, then it could be broken down to this (where the decryption method might need to be adjusted, depending on the cookie component configuration):
$data = substr($data, 8);
$data = base64_decode($data);
$data = Security::cipher($data, Configure::read('Security.salt'));
$first = substr($data, 0, 1);
if ($first === '{' || $first === '[') {
$decoded = json_decode($data, true);
if($decoded !== null) $data = $decoded;
}
However this heavily relies on the cookie component internals and configuration, so again, this is anything but recommended!

Related

Define php variable at php initialization

I'm currently coding one of my first php applications.
The application has to connect to a LDAP server and change some user attributes in the directory.
That application has some parameters to read in a mySQL Database in order to run.
Some examples of these parameters could be:
-LDAP Address
-LDAP Service Account
-LDAP Password
there are much more parameters, which rule, for example, the way users authenticate to my application,...
Currently, the database is read at each user session initialization, but, it doesn't have any sense because parameters do not vary from a session to another.
So, i'm looking for a way to load these parameters from the database, only one time (for example, at the php service initialization), and access to these parameters in the "normal" php code through variables.
What would be the best way to do this?
Thank you in advance.
You are looking for a persistent cross-request storage. There are many options for this.
The simplest is APCu (which can be used in conjunction with Zend OpCache, or for PHP < 5.5, APC).
Simply:
if (apc_exists('mykey')) {
$data = apc_fetch('mykey');
} else {
// create it from scratch
apc_store('mike', $data);
}
$data can be most any PHP type, arrays, objects, or scalars.
You can even put this code in the auto_prepend_file INI setting so it is run automatically on every request.
However: this is per server (and per SAPI, so mod_php/php-fpm/cli don't share the cache) so you will have to create it once per server.
Alternatively, for a multi-server setup you can use something like memcached or redis. These are stand-alone daemons that will let you store arbitrary key/value pairs of string data (so you may need to serialize()/unserialize() on the values).
I personally prefer memcache, which has two extensions for PHP, pecl/memcached and pecl/memcache (I prefer pecl/memcached, it has more features).
Both of them are pretty simple.
pecl/memcached:
$memcache = new Memcached();
$memcache->addServer('localhost', '11211');
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
pecl/memcache:
$memcache = new Memcache();
$memcache->connect(); // uses localhost:11211, the default memcache host/port
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
Both extensions support storage of arrays and objects without serialization.
You can of course store multiple keys with any of these solutions and just pull them all, instead of using one, or one with an array/object.
You can use Memcache do cache database requests. See here how to use.
Another way is using Php Sessions.
<?php
session_start(); // need to be before any html code
$_SESSION['something'] = 'Something here...';
echo $_SESSION['something']; // will show "Something here..."
And you can remove using...
unset($_SESSION['something']);
You also can use cookies, using the function setcookie. See here.
And you can get cookies using...
echo $_COOKIE['something'];
Production mode
In a production mode, this will work as set_transient of Wordpress. You will do the first db request to get the value and will cache this value using cookies, sessions or memcache.
If you want to show this values inside of your page, you can use a standard caching library.
My understanding of the question is that you have some SQL data that is more or less constant and you don't want to have to read that in from the SQL connection on every request.
If that is the case you can use memcache to store the data:
http://php.net/manual/en/book.memcache.php
The data will still be persistent and you will only need to go to the database if the cached data isn't there or needs to be refreshed.
If the data is specific to a particular user you can just use a session.
http://php.net/manual/en/book.session.php
http://php.net/manual/en/session.examples.basic.php
If this is only to be used when starting up your server (so once and done) and you don't want to bother to with memcached/xcache (as they would be over kill) you can still use environment variables. See get_env

Traverse array structure with string

Can I store a pre-made array traversal?
I want to store several API calls, and also how I get to the relevant information from their response.
For example:
$url = 'http://maps.googleapis.com/maps/api/elevation/json?locations='.$location->$latitude.','.$location->$longitude.'&sensor=true';
$response = json_decode(file_get_contents($url), true);
$result = $response['results'][0]['elevation'];
Can I save this part as a string, for storage in my DB or a variable:
$elevation = "['results'][0]['elevation']";
Then later somehow use it to parse the response, ie.
$result = $response[$elevation];
The answer is no, sorry ! you will need to store your $response as it is and call it later on using the correct format $response['results'][0]['elevation']
You may however want to use serialize() if the problem is about how to persist the array into your database:
$db->insert(serialize($reponse));
then when you retrieve the response from your db use unserialize:
$response=unserialize($db->fetchReponse());
$elevation=$response['results'][0]['elevation'];
EDIT
Based on your comment below it seems what you need is a Cache. Whereby prior to sending the request to the web service API, your application checks in a cache to see if you already have the data available locally. As above example you would most likely want to serialize the PHP array or simply cache the raw response, given that it is in JSON format (PHP serialization will create something very similar anyway).
You would create the Cache key from the query params : location, etc.
Your cached object can be stored in a DB if you choose or on the file system, or even in Memory.
Check out ZF2 Cache component :
http://framework.zend.com/manual/2.0/en/modules/zend.cache.storage.adapter.html

How to use Request::factory()->execute() to call an script from another library in the same host

I'm using Kohana 3.2, and I want to be able to call another script (unrelated to Kohana, outside of its 'jurisdiction') that returns a application/json response.
When I tried using:
$response = json_decode(Request::factory('/scripts/index.php?id=json')->execute()->body());
It errors out saying there's no route to scripts/index.php. So I tried using Request_Client_External
Request_Client_External::factory()->execute(Request::factory('/scripts/index.php?page=s'))->body();
Gives me Request_Exception [ 0 ]: Error fetching remote /scripts/index.php?page=s [ status 0 ] Could not resolve host: scripts; Host not found. It appears it need a full flagged URL using http/https, but how to avoid the overhead of it doing a real external request?
Doing a
Request::factory(url::site('/scripts/index.php?page=s', 'http'))->execute()
works but is it considered "external"?
The short answer to your question is that the only way to use Request::factory()->execute() to achieve that is to use pass it the full url (with whatever "overhead" that entails, which shouldn't be too much: your server's probably quite good at talking to itself).
Otherwise, ideally you'd put the functionality of scripts into a library and call that from Kohana. However it sounds like that's not an option for you. If you have to leave /scripts/index.php untouched and insist on an 'internal' request, you could use PHP's output buffering, as illustrated below. But there are a bunch of caveats so I wouldn't recommend it: the best way is passing a full url.
// Go one level deeper into output buffering
ob_start();
// Mimic your query string ?id=json (see first caveat below)
$_GET = $_REQUEST = array('id' => 'json');
// Get rid of $_POST and $_FILES
$_POST = $_FILES = array();
// Read the file's contents as $json
include('/scripts/index.php');
$json = ob_get_clean();
$response = json_decode($json);
Some caveats.
Firstly, the code changes $_GLOBALS. You probably don't use these in your Kohana code (you use $this->request->get() like a good HMVCer, right?). But in case you do, you should 'remember' and then restore the values, putting $old_globals = $GLOBALS; etc. before the above code, and $GLOBALS = $old_globals; after.
Sessions: if your /scripts/index.php uses `session_start() this will cause a warning if you've already started a session at this point in Kohana.
Note that all variables set in scripts/index.php will remain set in the context you're in. If you want to avoid possible conflicts with that context, you'd start a new context, i.e. wrap the above into its own function.
Finally, you'd also need to make sure that /scripts/index.php doesn't do anything like Kohana::base_url = 'something_else', or touch any other static attributes, or do something catastrophic using this.

PHP: persistent variable value

I have to read a file and do some computation, than save the result of this computation inside a variable.
I just need to do this once. In Java + Servlet I can do this using a servlet container and, for instance, the singleton pattern.
I know that in PHP I can't act like this. Which is the better way to do this? Save the computation (or transfer the data) on DB?
No, it won't work like with Java Servlets. You'll have to find a workaround.
First, I assume that using $_SESSION, $_COOKIE or $_REQUEST in general isn't practicable to you as you want to save the state per server (or per application) and not per 'User Session'.
Using a database sounds practicable in your case. In a regular application design it will be the most common solution.
Also you can do something like this, using the serialization capabilities of PHP:
<?php
$resultfile = 'result.dat';
if(!file_exists($resultfile)) {
$result = compute_result('foo bar');
file_put_contents($resultfile, serialize($result));
} else {
$result = unserialize(file_get_contents($resultfile));
}
Using PHP's serialize() attempt is especially practicable when
You are in a PHP only environment
$result is a complex datatype but you don't want to create a database structure and map $result too it
If you are not in a PHP only environment you might prefer other serialization formats as JSON or XML.
Also the serialization result can be stored as a string in a database instead of a file. Saving it to a database instead of a file would make the application more scalable as the result would be available to all servers that access the same database (cluster).
In short: I would suggest using a database maybe combined with serialization.

Accessing php $_SESSION from python (wsgi) - is it possible?

I've got a python/WSGI app which needs to check to see if a user has logged on to a PHP web app. The problem is that the PHP app checks if a user has logged on by comparing a value in the $_SESSION variable to a value in the cookie from the user's browser. I would prefer to avoid changing the behavior of the php app if at all possible.
My questions:
Is there anyway I can access the session variables from within python? Where should I start to look?
Are there any obvious security/performance issues I should be aware of when taking this approach?
yep. session (in default) is a regular file. so all what you need is look over session directory and find file with name of session cookie value. then - you have to implement php-like serialize/unserialize and do whatever you want.
nope
Depends on the PHP app, if it's keeping session data in a database (MySQL maybe) you can just connect to the database and get the data, if it's using native PHP sessions you should look to the session.save_path config setting in php.ini, that's the place where the runtime saves files with the session data.
Once you have the data you can parse it to get it unserialized, take a look at how serialize() and unserialize() work in PHP.
I'm currently in the process of trying to run a python server side by side with an existing Apache/php one. A custom solution I arrived at was to save the $_SESSION as an encrypted cookie, letting the php authentication operate as before, then share a private key between the two servers.
Two issues:
Up to you how to handle session expiry stuff.
I haven't bothered with an Initialization Vector, assuming the time stamp from my expiry stuff is enough. See https://stackoverflow.com/a/12486940/4495503 for why I might be being too security lax...
Anyway, my php encrypted cookie function:
session_start();
$encryptToCookie = function($varToEncode,$cookieName,$privateKey){
$iv = $privateKey;
$pass = $privateKey;
$method = 'aes-128-cbc';
$encryptedString = openssl_encrypt(json_encode($varToEncode), $method, $pass, true, $iv);
setcookie($cookieName,bin2hex($encryptedString));
};
$encryptToCookie($_SESSION,"sessionEncrypted","yohoyohoyohoyoho"); // private key must be 16bit
And my python side decryption:
from subprocess import Popen, PIPE
import binascii
def decrypt(encryptedString,privateKey):
encryptedString = binascii.unhexlify(encryptedString)
pathToOpenSSL = 'C:\pysrc\openssl\openssl.exe' # MODIFY THIS!!
openssl = Popen([pathToOpenSSL,
'enc','-aes-128-cbc','-d',
'-nosalt','-nopad','-K',
privateKey.encode('hex'),
'-iv',
privateKey.encode('hex')],
stdin=PIPE,stdout=PIPE)
decryptedString = openssl.communicate(encryptedString)[0].replace('\x04','')
return decryptedString
decrypt(encryptedString,'yohoyohoyohoyoho')
Hope this is of help to someone, remember all the usual stuff about generating private keys and then being careful with them!

Categories